- 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
@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 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 beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
if (logger.isInfoEnabled()) {
List 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注册ServiceBeandoScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { // 查找满足要求的候选组件Dubbo Service Class // 对basePackage路径下所有类经过isCandidateComponent筛选 // 先经过excludeFilters(优先),再经过includeFilters Set 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 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 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 attributes) {
Map 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的实例化请见下文分析。



