Dubbo学习之DubboService
相关阅读
- Dubbo学习之PostProcessor
- Dubbo学习之DubboReference
- Dubbo学习之ReferenceBean
- Dubbo学习之ServiceBean
简介
本文基于Spring Boot 2.6.6
,dubbo-spring-boot-starter 3.0.6
环境。
本文主要分析Dubbo中注解DubboService
的使用方式,并从源码分析其生效的实现原理;
使用
常用的使用方式有两种,下面分别介绍;
方式一
在实现类上使用@DubboService
,表示该Bean为Dubbo Service,示例代码如下:
@DubboService
public class DemoServiceImpl implements DemoService {}
方式二
官方推荐在BeanMethod上使用@DubboService
;
示例代码如下:
@Configuration
public class ReferenceConfig {@Bean@DubboServicepublic DemoService demoServiceImpl() {return new DemoServiceImpl();}
}
解析
注解DubboService
的解析由ServiceAnnotationPostProcessor
完成,它会将标注了@DubboService
的类或者Bean以ServiceBean
形式注册到Spring容器中,以便后续创建Dubbo Service;
- 其
postProcessBeanDefinitionRegistry
方法用于解析方式一的@DubboService
; - 其
postProcessBeanFactory
方法用于解析方式二的@DubboService
;
方式一
ServiceAnnotationPostProcessor
实现了BeanDefinitionRegistryPostProcessor
接口,在其postProcessBeanDefinitionRegistry
方法中,会根据设置的resolvedPackagesToScan
(待扫描路径),处理对应路径下标注了@DubboService
(本文仅关注DubboService
,实际还包括:org.apache.dubbo.config.annotation.Service
、com.alibaba.dubbo.config.annotation.Service
)的类,代码如下:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {this.registry = registry;// 扫描resolvedPackagesToScan路径下标注了@DubboService的类// packagesToScan由参数dubbo.scan.base-packages配置// 若该参数不存在,那么ServiceAnnotationPostProcessor也不会存在于Spring容器scanServiceBeans(resolvedPackagesToScan, registry);
}private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {// 设置扫描标识,避免重复扫描scaned = true;if (CollectionUtils.isEmpty(packagesToScan)) {// 无路径需要扫描,则直接退出if (logger.isWarnEnabled()) {logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");}return;}// 配置DubboClassPathBeanDefinitionScannerDubboClassPathBeanDefinitionScanner scanner =new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);scanner.setBeanNameGenerator(beanNameGenerator);for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {// 基于注解的类型过滤器scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));}ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();scanner.addExcludeFilter(scanExcludeFilter);// 扫描各个包路径for (String packageToScan : packagesToScan) {// 如果已经扫描过则跳过if (servicePackagesHolder.isPackageScanned(packageToScan)) {if (logger.isInfoEnabled()) {logger.info("Ignore package who has already bean scanned: " + packageToScan);}continue;}// 扫描包路径下被Dubbo Service注解标注的类,并生成BeanDefinitionscanner.scan(packageToScan);// 查找Dubbo Service的BeanDefinitionHolder// 结果会在scan中缓存,故此次直接从缓存中得到Set<BeanDefinitionHolder> beanDefinitionHolders =findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {if (logger.isInfoEnabled()) {List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());}logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);}for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {// 向容器中注册该beanDefinitionHolderprocessScannedBeanDefinition(beanDefinitionHolder, registry, scanner);// 缓存已扫描过的类servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());}} else {if (logger.isWarnEnabled()) {logger.warn("No class annotated by Dubbo @Service was found under package ["+ packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());}}// 缓存已扫描过的包路径servicePackagesHolder.addScannedPackage(packageToScan);}
}
主要逻辑为:
- 扫描标注
@DubboService
的Class,并注册到Spring容器; - 将注册的
BeanDefinition
,再以ServiceBean
注册到Spring容器
扫描标注@DubboService的Class
ClassPathBeanDefinitionScanner.scan(packageToScan)
内部使用doScan
实现,其代码如下:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {// 查找满足要求的候选组件Dubbo Service Class// 对basePackage路径下所有类经过isCandidateComponent筛选// 先经过excludeFilters(优先),再经过includeFiltersSet<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 校验当前容器是否已存在该BeanDefinition// 1. 若不存在则校验通过// 2. 若存在,但兼容,则校验不通过// 3. 若存在,且不兼容,则抛出异常if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册BeanDefinition,此时beanName根据原始类名生成registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;
}
注册ServiceBean
processScannedBeanDefinition
代码如下:
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,DubboClassPathBeanDefinitionScanner scanner) {Class<?> beanClass = resolveClass(beanDefinitionHolder);// 获取类上标注的Dubbo Service注解Annotation service = findServiceAnnotation(beanClass);// 获取注解的属性Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();// 构造ServiceBean BeanName// ServiceBean:interfaceNameString beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);// 构造ServiceBean BeanDefinitionAbstractBeanDefinition serviceBeanDefinition =buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);// 注册ServiceBean BeanDefinition// 此时beanName为ServiceBean:interfaceNameregisterServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);
}
方式二
ServiceAnnotationPostProcessor.postProcessBeanFactory
方法中,会处理标注了@DubboService
(本文仅关注DubboService
,实际还包括:org.apache.dubbo.config.annotation.Service
、com.alibaba.dubbo.config.annotation.Service
)的BeanMethod
,代码如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if (this.registry == null) {// 未在postProcessBeanDefinitionRegistry中设置,则此时设置this.registry = (BeanDefinitionRegistry) beanFactory;}// 处理由标注了Dubbo Service注解的BeanMethod得到的BeanDefinitionString[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);// 存在则说明BeanMethod上存在Dubbo Service注解if (annotationAttributes != null) {// 注册为Dubbo Service BeanDefinitionprocessAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);}}if (!scaned) {// 还未扫描过,则扫描scanServiceBeans(resolvedPackagesToScan, registry);}
}private void processAnnotatedBeanDefinition(String refServiceBeanName, AnnotatedBeanDefinition refServiceBeanDefinition, Map<String, Object> attributes) {Map<String, Object> serviceAnnotationAttributes = new LinkedHashMap<>(attributes);// get bean class from return typeString returnTypeName = SpringCompatUtils.getFactoryMethodReturnType(refServiceBeanDefinition);Class<?> beanClass = resolveClassName(returnTypeName, classLoader);String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);// 构造ServiceBean BeanName// ServiceBean:interfaceNameString serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, refServiceBeanName);// set idserviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);// 注册ServiceBean BeanDefinition// 此时beanName为ServiceBean:interfaceNameregisterServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, serviceInterface);
}
至此,@DubboService
的源码分析就结束啦,ServiceBean
的实例化请见下文分析。
Dubbo学习之DubboService相关推荐
- 【七夕特殊礼物】Dubbo学习之SPI实战与debug源码
目录 绪论 环境搭建 dubbo-demo-interface dubbo-demo-xml dubbo-demo-xml-provider 源码跟踪 getExtension createExten ...
- dubbo学习--导入eclipse异常Unbound classpath container(2)
2019独角兽企业重金招聘Python工程师标准>>> dubbo学习--导入eclipse异常Unbound classpath container(2) 标签(空格分隔): du ...
- 淘宝SOA框架dubbo学习(2)--搭建Zookeeper注册中心服务
2019独角兽企业重金招聘Python工程师标准>>> 继上一篇博文, 淘宝SOA框架dubbo学习(1) http://my.oschina.net/hanshubo/blog/3 ...
- dubbo学习视频资料
dubbo学习视频资料 请叫我小橙,橙橙 偶遇青春 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成. ...
- dubbo学习之服务消费者
1.简介 上节讲了如何发布一个dubbo服务,这节主要讲如何进行消费,创建一个消费者. 2.详细步骤 2.1 项目目录结构 2.2 创建maven项目 这里演示时其实通过一个main方法就可以了,没必 ...
- Dubbo学习总结(2)——Dubbo架构详解
2019独角兽企业重金招聘Python工程师标准>>> 一.前言 部门去年年中开始各种改造,第一步是模块服务化,这边初选dubbo试用在一些非重要模块上,慢慢引入到一些稍微重要的功能 ...
- 【转载保存】dubbo学习笔记
Dubbo Dubbo简介 首先,我理解的Dubbo,从大的方向来看是单体应用到分布式应用过度期的一个产物,具体来说应该是分布式应用从早期的SOA到微服务过度的一个产物. 在编写分布式场景下高并发.高 ...
- dubbo学习之事件通知实践
目录 实践 dubbo-demo-interface dubbo-demo-xml-provider notify-provider.xml UserNotifyServiceImpl Provide ...
- dubbo学习之源码创建属于自己的dubbo-demo
目录 绪论 环境搭建 dubbo-demo-interface dubbo-demo-xml dubbo-demo-xml-provider dubbo-demo-xml-consumer 运行 绪论 ...
最新文章
- ICML2020 | PGFS:如何保证生成分子是可合成的?强化学习来帮忙
- boost::program_options模块实现支持自定义选项语法的测试程序
- java web 润乾报表教程_润乾报表开发 基础教程.ppt
- linux ulimit
- bzoj 1597 [Usaco2008 Mar]土地购买——斜率优化dp
- 8分钟答辩稿_教资面试!各科试讲逐字稿!背就稳了!
- 错误: 找不到或无法加载主类 helloworld_你还不知道Java的类加载机制?
- Object-C 学习笔记(IOS程序设计课程)01
- 《设计模式详解》手写简单的 Spring 框架
- PowerPhotos:Mac照片库管理软件
- CSS实现三角形的方法--拓展
- Visual Studio(VS2017/VS2019) C++ 配置 CPLEX 教程
- android设置wifi蓝牙共享网络,Android无线网络共享设置指南
- dnf打团正在连接服务器进不去是吗鬼,DNF韩服大转移版本开启 上线送迷你女鬼剑宠物...
- 调用阿里云语音识别接口
- 基于python的网络聊天室论文_基于python的聊天室(2),实现,二
- 大学慕课MOOC设计一个简单的计算工具
- swf转Word小技巧
- 本地玩邮件服务器和邮件客户端
- Python药店销售数据分析