赞
踩
本文基于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
@DubboService
public 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; } // 配置DubboClassPathBeanDefinitionScanner DubboClassPathBeanDefinitionScanner 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注解标注的类,并生成BeanDefinition scanner.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) { // 向容器中注册该beanDefinitionHolder processScannedBeanDefinition(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容器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(优先),再经过includeFilters Set<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; }
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:interfaceName String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface); // 构造ServiceBean BeanDefinition AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName); // 注册ServiceBean BeanDefinition // 此时beanName为ServiceBean:interfaceName registerServiceBeanDefinition(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得到的BeanDefinition String[] 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 BeanDefinition processAnnotatedBeanDefinition(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 type String returnTypeName = SpringCompatUtils.getFactoryMethodReturnType(refServiceBeanDefinition); Class<?> beanClass = resolveClassName(returnTypeName, classLoader); String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass); // 构造ServiceBean BeanName // ServiceBean:interfaceName String serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface); AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, refServiceBeanName); // set id serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName); // 注册ServiceBean BeanDefinition // 此时beanName为ServiceBean:interfaceName registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, serviceInterface); }
至此,@DubboService
的源码分析就结束啦,ServiceBean
的实例化请见下文分析。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。