相关阅读
简介
本文基于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容器
扫描标注@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(优先),再经过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;
}
注册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: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
的实例化请见下文分析。