上篇我们介绍了Dubbbo整合Spring中的@EnableDubboConfig注解源码分析,地址如下
Dubbo源码解读-dubbo启动与Spring整合-CSDN博客。
本文主要针对@ DubboComponentScan注解,从dubbo源码角度解析该注解功能。
接着说明,读Dubbo源码最好是先对Spring源码有一定的了解。如果大家需要,我也可以针对Spring框架做一系列源码的解读专栏。
不过不用担心,如果需要Spring的源码知识,文章中也会进行Spring源码铺垫介绍的。
如果内容中有没描述清楚的,或者大家在阅读源代码有疑问的,欢迎留言,看到就会及时回复。
为了更清楚的分析解释源码,源代码中部分不重要的内容可能会删减,保留重要内容方便大家理解。
主要内容
- @ DubboComponentScan解析
- ServiceAnnotationBeanPostProcessor源码解析
- ReferenceAnnotationBeanPostProcessor源码解析
@DubboComponentScan解析
该标签的主要职责其实就是负责注册两个BeanPostProcessor,分别是ServiceAnnotationBeanPostProcessor和ReferenceAnnotationBeanPostProcessor,分别负责处理@Service和@Reference注解。
具体流程如下:
-
注解上import了DubboComponentScanRegistrar类。
-
DubboComponentScanRegistrar实现了ImportBeanDefinitionRegistrar接口,会在Spring启动过程中,调用registerBeanDefinitions方法()
-
注册ServiceAnnotationBeanPostProcessor类BeanDefinition
-
注册ReferenceAnnotationBeanPostProcessor类BeanDefinition
Spring背景知识铺垫
Spring容器管理的类,不论是通过xml加载的还是注解加载的,都需要先进行收集成Beandefinetion对象,然后再根据该对象进程Bean 的实例化。实例化完成之后交给Spring管理。
- @Import注解对应的类会在,Spring启动过程中由 ConfigurationClassPostProcessor扫描,收集@Import注解
- 实现ImportBeanDefinitionRegistrar的类,在Spring启动过程中ConfigurationClassPostProcessor调用对应类中的registerBeanDefinitions()方法如DubboComponentScanRegistrar中的
源码流程
- 流程1
#Import标签倒入注册类
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
}
- 流程2 /3/4
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); //注册ServiceAnnotationBeanPostProcessor registerServiceAnnotationBeanPostProcessor(packagesToScan, registry); 注册ReferenceAnnotationBeanPostProcessor registerReferenceAnnotationBeanPostProcessor(registry); } }
ServiceAnnotationBeanPostProcessor
负责对@Service注解支持。
具体流程:
- 创建DubboClassPathBeanDefinitionScanner继承自ClassPathBeanDefinitionScanner
- doScan对包下面的类进行扫描,获取所有包含@service注解的类,并封装成BeanDefinition,注册到Registry中
- 创建ServiceBean类的BeanDefinition(每个@service注解的类都对应一个ServiceBean)
- 根据@service注解,填充ServiceBean的BeanDefinition的属性。
- .class属性.interface,ref等
- 注册
- 特殊说明:一个@Service注解修饰的类,会对应两个beanDefinition.上面2/3。
Spring背景知识铺垫
- Spring通过BeanPostProcessor实现在启动过程中的埋点功能,比如手机@autowire注解,@resource,完成IOC,创建AOP代理等。
- 实现BeanDefinitionRegistryPostProcessor的类会在Spring创建完BeaFacotry之后,执行invokeBeanFactoryPostProcessors会调用BeanDefinitionRegistryPostProcessor实现类对应的registryPostProcessor()方法
- 上面2中具体流程Application.refresh()->invokeBeanFactoryPostProcessors()->BeanDefinitionRegistryPostProcessor.registryPostProcessor()
源码流程
- ServiceAnnotationBeanPostProcessor.postProcessBeanDefinitionRegistry
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//解析扫描包 com.*.*
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
//创建扫描器,进行扫描
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
- ServiceAnnotationBeanPostProcessor.registreServiceBeans流程2/3/4
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
//设置要扫描的注解 。这里就是@Servcie注解
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
for (String packageToScan : packagesToScan) {
// 这个方法比较庞大。具体流程就是:
//1.先扫描路径下所有的class文件
//2.查看class上面是否有对应的@service注解
//3.创建BeanDefinition对象
//4.绑定属性值
//5.注册BeanDefinition.
scanner.scan(packageToScan);
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
//这里会针对每个被@Service修饰的类,创建一个ServiceBean类型的BeanDefinition.
registerServiceBean(beanDefinitionHolder, registry, scanner);
}
}
}
}
ReferenceAnnotationBeanPostProcessor
负责对@Reference的支持
具体流程
- 收集@reference注解元数据
- 完成依赖注入
Spring背景知识铺垫
BeanPostProcessor知识点:
- 实现MergedBeanDefinitionPostProcessor接口会在Spring启动过程中,bean创建实例之后调用postProcessMergedBeanDefinition方法。
- 实现InstantiationAwareBeanPostProcessor类会在Spring启动过程中,通过populateBean()调用postProcessProperties()方法完成IOC依赖注入。
注解依赖注入实现流程
- 自定义BeanPostProcessor
- 收集注解:实现MergedBeanDefinitionPostProcessor重写postProcessMergedBeanDefinition方法。
- 依赖注入:继承InstantiationAwareBeanPostProcessor重写postProcessProperties方法
源码流程
- 收集@Reference。类调用关系:ReferenceAnnotationBeanPostProcessor->AnnotationInjectedBeanPostProcessor.postProcessMergedBeanDefinition()->findInjectionMetadata()->buildAnnotatedMetadata()
private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
//收集类中被@Reference的字段
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
//收集类中被@Reference修饰的方法
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
//包装成InjectMetadata对象,持有上面两个集合,方便后面依赖注入
return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
- 完成依赖注入:拿到上一步收集结果,对有@Reference注解的属性和方法进行依赖注入.类调用关系:ReferenceAnnotationBeanPostProcessor->AnnotationInjectedBeanPostProcessor.postProcessPropertyValues()
//AnnotationInjectedBeanPostProcessor.class
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//收集有@Reference注解的属性和方法 copy的spring代码
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
}
return pvs;
}
//AnnotationInjectedBeanPostProcessor.class
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = field.getType();
//获取需要依赖注入的实例
injectedBean = getInjectedObject(annotation, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedBean);
}
//ReferenceAnnotationBeanPostProcessor.class
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
//创建referencedbean的名称
String referencedBeanName = buildReferencedBeanName(reference, injectedType);
//创建ReferenceBean
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
//field和method的injectedElement,和ReferenceBean建立缓存
cacheInjectedReferenceBean(referenceBean, injectedElement);
//创建需要依赖注入的代理实例
Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);
return proxy;
}
总结:上面内容中,每个注解都从业务流程和源码角度进行了详细分析,依赖的Spring源码知识点也做了说明,如果大家有疑问或者对文章排版任何方面有建议都可以留言评论,看到都会及时回复大家。
知识总结,分享不易,全文手敲,欢迎大家点赞评论收藏。