![cover](https://img-blog.csdnimg.cn/img_convert/1f20816e15694cf3b56262c1f87e2a14.png)
Spring整合Dubbo,@Service注解源码解析
在@DubboComponentScan注解上导入了一个DubboComponentScanRegistrar类,该类实现了ImportBeanDefinitionRegistrar接口,因此会调用到其对应的registerBeanDefinitions方法,主要就是分成三步,第一步是对传入的路径进行扫描,得到一个个的BeanDefinition,第二步是扫描包路径下加了@Service注解的类并
在Spring中使用Dubbo非常简单,只要在配置类上加上对应的@EnableDubbo注解便可使用Dubbo相关的功能,这个注解添加了其他两个注解,一个是@EnableDubboConfig,将Dubbo相关的配置项全部整合成Config对应的类(可以参考Spring整合Dubbo配置项源码解析)另一个是@DubboComponentScan,可以通过传入的包路径逐个扫描下面的类,并且逐步解析@Service和@Reference注解,本文就来讲解一下@DubboComponentScan中和@Service相关的功能。
在@DubboComponentScan注解上导入了一个DubboComponentScanRegistrar类,该类实现了ImportBeanDefinitionRegistrar接口,因此会调用到其对应的registerBeanDefinitions方法,主要就是分成三步,第一步是对传入的路径进行扫描,得到一个个的BeanDefinition,第二步是扫描包路径下加了@Service注解的类并且加以相关的处理逻辑,第三步是处理加了@Reference注解的类;
1.getPackagesToScan这里面可以理解为就是return了@DubboComponentScan中的basePackages和basePackageClasses
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("执行DubboComponentScanRegistrar");
// 拿到DubboComponentScan注解所定义的包路径,扫描该package下的类,识别这些类上
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 注册ServiceAnnotationBeanPostProcessor一个Bean
// 实现了BeanDefinitionRegistryPostProcessor接口,所以在Spring启动时会调用postProcessBeanDefinitionRegistry方法
// 该方法会进行扫描,扫描@Service注解了的类,然后生成BeanDefinition(会生成两个,一个普通的bean,一个ServiceBean),后续的Spring周期中会生成Bean
// 在ServiceBean中会监听ContextRefreshedEvent事件,一旦Spring启动完后,就会进行服务导出
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 注册ReferenceAnnotationBeanPostProcessor
// 实现了AnnotationInjectedBeanPostProcessor接口,继而实现了InstantiationAwareBeanPostProcessorAdapter接口
// 所以Spring在启动时,在对属性进行注入时会调用AnnotationInjectedBeanPostProcessor接口中的postProcessPropertyValues方法
// 在这个过程中会按照@Refrence注解的信息去生成一个RefrenceBean对象
registerReferenceAnnotationBeanPostProcessor(registry);
}
2.registerServiceAnnotationBeanPostProcessor(),看这个方法名盲猜一下是注册了ServiceAnnotationBeanPostProcessor这么个东西,看一下里面的逻辑。
第一行代码就证明了上面的盲猜是对的,后面就是为这个BeanDefinition添加传参和生成beanName,看起来就没什么特殊的逻辑了,所以这边代码就走完了,没什么相关的逻辑,只能去看一下ServiceAnnotationBeanPostProcessor这里面是否继承或者实现了什么接口和类
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 生成一个RootBeanDefinition,对应的beanClass为ServiceAnnotationBeanPostProcessor.class
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
// 将包路径作为在构造ServiceAnnotationBeanPostProcessor时调用构造方法时的传入参数
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
这边就可以看到实现了BeanDefinitionRegistryPostProcessor接口(这块是和Spring相关的逻辑,在Spring启动的时候会统一调用这里面的postProcessBeanDefinitionRegistry方法),然后代码就会走到ServiceAnnotationBeanPostProcessor.registerServiceBeans方法中
registerServiceBeans方法中会先生成扫描器,然后添加要扫描的注解,后面两步则是对扫描到的类生成相应的BeanDefinition,然后注册
findServiceBeanDefinitionHolders方法中核心逻辑在于findCandidateComponents方法,对传入的路径进行扫描并且返回相应的BeanDefinition,这块相对于的源码逻辑如下(Spring源码解析),经过这个方法之后便会得到对应的BeanDefinition,但是此时还没有生成Bean,只是一个空壳子而已,所以最后处理逻辑是在registerServicebean方法中
private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(
ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry,
BeanNameGenerator beanNameGenerator) {
Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);
Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<>(beanDefinitions.size());
for (BeanDefinition beanDefinition : beanDefinitions) {
String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
beanDefinitionHolders.add(beanDefinitionHolder);
}
return beanDefinitionHolders;
}
registerServicebean中第一步会先得到@Service注解中配置的那些参数,然后会根据这些参数调用buildServiceBeanDefinition方法生成一个ServiceConfig,(先别管这个ServiceConfig是什么东西,他已经生成了),在生成ServiceConfig过程中会添加一个ref属性,这边是只会放一个beanName进去,后续在Spring的生命周期中会通过这个beanName找到其对应的Bean然后覆盖,最后再将其注册进去,所以这边可以看到实际上是生成了两个Bean。
1. ⼀个就是服务实现类本身⼀个Bean对象
2. ⼀个就是对应的ServiceBean类型的⼀个Bean对象,最后也是会将这个类导出到注册中心(Dubbo服务导出源码解析
)
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
// 生成一个ServiceBean
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
// 把ServiceBean注册进去,对应的beanName为ServiceBean:org.apache.dubbo.demo.DemoService
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
并且需要注意的是,ServiceBean实现了ApplicationListener接⼝,所以当Spring启动完成后会触发 onApplicationEvent()⽅法的调⽤,⽽在这个⽅法内会调⽤export(),这个⽅法就是服务导出的入口。
更多推荐
所有评论(0)