- 一、前言
- 二、 Dubbo 的自动装配
- 三、提供者的启动流程
- 1. ServiceAnnotationBeanPostProcessor
- 1.1 registerBeans
- 1.2 resolvePackagesToScan
- 1.3 registerServiceBeans
- 1.3.1 registerServiceBean
- 1.4 总结
- 2. DubboBootstrapApplicationListener
- 四、消费者的启动流程
- 1. ReferenceAnnotationBeanPostProcessor
- 1.1 构造函数
- 1.2 ReferenceAnnotationBeanPostProcessor#postProcessPropertyValues
- 1.2.1 AbstractAnnotationBeanPostProcessor#findInjectionmetadata
- 1.2.2 Injectionmetadata#inject
- 1.2.3 AbstractAnnotationBeanPostProcessor#getInjectedObject
本系列为个人Dubbo学习笔记,内容基于《深度剖析Apache Dubbo 核心技术内幕》, 过程参考官方源码分析文章,仅用于个人笔记记录。本文分析基于Dubbo2.7.0版本,由于个人理解的局限性,若文中不免出现错误,感谢指正。
系列文章地址:Dubbo源码分析:全集整理
本文基于 Dubbo 2.7.5 版本。
二、 Dubbo 的自动装配在Springboot 集成 Dubbo 时需要引入如下依赖:
org.apache.dubbo dubbo-spring-boot-starter 2.7.5
而 dubbo-spring-boot-starter 会引入如下两个依赖
org.apache.dubbo dubbo-spring-boot-autoconfigure 2.7.5 org.apache.dubbo dubbo-spring-boot-autoconfigure-compatible 2.7.5
上面的两个依赖会通过Springboot的自动装配引入Dubbo的自动装配类:DubboAutoConfiguration、DubboRelaxedBindingAutoConfiguration、DubboRelaxedBinding2AutoConfiguration。
如下图:
关于Springboot的 自动装配,如有需要详参: Spring源码分析十一:Springboot 自动装配。
上面我们看到, Dubbo通过 Springboot的 自动装配引入了下面几个类:
- DubboAutoConfiguration : 用于引入 Dubbo的 配置类。包括 ServiceAnnotationBeanPostProcessor、ReferenceAnnotationBeanPostProcessor、SingleDubboConfigConfiguration、MultipleDubboConfigConfiguration、primaryPropertyResolver 等
- DubboRelaxedBindingAutoConfiguration :注入了宽松配置解析器,用于Springboot 1.x 版本, 解析 Dubbo 的配置
- DubboRelaxedBinding2AutoConfiguration : 功能同 DubboRelaxedBindingAutoConfiguration,用于 Springboot 2.x 版本,解析 Dubbo的配置
三、提供者的启动流程
Springboot 集成 Dubbo 后,下面我们以服务提供者的视角来看Dubbo服务暴露的流程:
- Springboot 启动时会激活 ServiceAnnotationBeanPostProcessor #postProcessBeanDefinitionRegistry 方法。此方法会向容器中注入DubboBootstrapApplicationListener(如果没有注册) 以及被 @Service (Dubbo 提供的 service 注解) 修饰的 Bean的 ServiceBean 的 BeanDefinition。
- 在容器刷新结束后,会通过 AbstractApplicationContext#finishRefresh 发送容器刷新结束事件(ContextRefreshedEvent),而 DubboBootstrapApplicationListener 会监听此事件,并调用 DubboBootstrap#start 方法来发布 Dubbo 服务。同时 DubboBootstrapApplicationListener 也监听 ContextClosedEvent 事件,用于停止服务暴露。
- DubboBootstrap#start 进行服务暴露。
上面的概述涉及到了 ServiceAnnotationBeanPostProcessor、DubboBootstrapApplicationListener 、DubboBootstrap 几个类,下面我们来看看 ServiceAnnotationBeanPostProcessor 和 DubboBootstrapApplicationListener 的实现,DubboBootstrap 由于篇幅限制,将留在下文中讲述(尚未成文)。
1. ServiceAnnotationBeanPostProcessorServiceAnnotationBeanPostProcessor 类结构如下:
ServiceAnnotationBeanPostProcessor 的作用有两个:
- 如果容器中没有 DubboBootstrapApplicationListener 的BeanDefinition,则向 Spring 容器中 注册 DubboBootstrapApplicationListener 的 BeanDefinition。
- 向 Spring 容器中 注册被 @Service 注解修饰的类对应的 ServiceBean 的 BeanDefinition。这里的@Service 指的是 Dubbo提供的 @Service注解。在 Spring 中 Dubbo会为每个被 @Service 注解修饰的类创建一个对应的 ServiceBean 来保存当前类暴露的一些信息。而 ServiceAnnotationBeanPostProcessor 会为这些 ServiceBean 生成对应的 BeanDefinition 保存到容器中。
注: Spring在容器中创建Bean时依赖于 BeanDefinition。简单来说,Spring在创建容器中的 Bean时首先会先创建BeanDefinition,随后根据BeanDefinition 再创建Bean,随后将Bean注入到容器中。所以这里创建的都是 BeanDefinition。
下面我们来详细分析:由于 ServiceAnnotationBeanPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,所以我们这里关注 postProcessBeanDefinitionRegistry 方法。
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// @since 2.7.5
// 1. 注册 DubboBootstrapApplicationListener BeanDefinition
registerBeans(registry, DubboBootstrapApplicationListener.class);
// 2. 获取指定的 Dubbo扫描路径
Set resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
// 3. 注册 ServiceBean
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
// 打印日志
}
}
我们按照上面的注释:
- registerBeans 将 DubboBootstrapApplicationListener 的 BeanDefinition 注册到容器中
- resolvePackagesToScan 获取到 Dubbo Bean的 扫描路径
- registerServiceBeans 扫描指定路径下的 Dubbo Bean ,生成对应的 BeanDefinition 注册到容器中。
下面我们详细来看每一步的具体实现。
1.1 registerBeansregisterBeans 方法的具体实现是 AnnotatedBeanDefinitionRegistryUtils#registerBeans,主要作用如果 DubboBootstrapApplicationListener BeanDefinition没有注册,则将 DubboBootstrapApplicationListener 的 BeanDefinition 注册到容器中。其实现如下:
// 入参 的 annotatedClasses 是 DubboBootstrapApplicationListener.class
public static void registerBeans(BeanDefinitionRegistry registry, Class>... annotatedClasses) {
if (ObjectUtils.isEmpty(annotatedClasses)) {
return;
}
// Remove all annotated-classes that have been registered
Iterator> iterator = new ArrayList>(asList(annotatedClasses)).iterator();
// 如果容器中已经存在 annotatedClass 的 BeanDefinition,则将其移除,不再进行下面的创建
while (iterator.hasNext()) {
Class> annotatedClass = iterator.next();
if (isPresentBean(registry, annotatedClass)) {
iterator.remove();
}
}
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
// 创建 annotatedClasses 的 BeanDefinition,并通过 registry 注册到容器中
reader.register(annotatedClasses);
}
1.2 resolvePackagesToScan
ServiceAnnotationBeanPostProcessor#packagesToScan 实现如下,主要作用是解析 Dubbo配置中的 dubbo.scan 配置的扫描路径并返回。
// 返回解析后的 dubbo.scan 指定的路径
private Set resolvePackagesToScan(Set packagesToScan) {
// 获取Dubbo bean 的扫描路径
Set resolvedPackagesToScan = new linkedHashSet(packagesToScan.size());
for (String packageToScan : packagesToScan) {
if (StringUtils.hasText(packageToScan)) {
// 替换 dubbo.scan 配置中的占位符
String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim());
resolvedPackagesToScan.add(resolvedPackageToScan);
}
}
// 返回解析后的扫描路径
return resolvedPackagesToScan;
}
1.3 registerServiceBeans
在该方法中, Dubbo会扫描 被 org.apache.dubbo.config.annotation.Service 和 com.alibaba.dubbo.config.annotation.Service 注解修饰的类(版本更高则可能是 DubboService),被这两个注解修饰的类会作为服务提供者暴露处理,而这里会生成对应服务的 ServiceBean BeanDefinition。
如:对于 ProviderServiceImpl,实现如下:
@Service(version = "1.0.0", group = "spring")
public class ProviderServiceImpl implements ProviderService {
@Override
public void sayHello() {
System.out.println("hello");
}
@Override
public void sayHello(String msg) {
System.out.println("hello msg = " + msg);
}
@Override
public String sayHelloWorld() {
System.out.println("hello world");
return "hello world";
}
}
在 Spring容器中会存在一个 ProviderServiceImpl 实例,同时会存在一个 ServiceBean 实例保存了ProviderServiceImpl 要暴露的服务信息,其中 ServiceBean 在 容器中的 beanName 生成规则是 ServiceBean:{接口路径}:{版本号}:{分组} ,如下图:
所以 ServiceAnnotationBeanPostProcessor#registerServiceBeans 这里是为了每个 Bean对应的 ServiceBean 生成对应的 BeanDefinition 并注册到容器中。
下面我们来看 ServiceAnnotationBeanPostProcessor#registerServiceBeans的实现,如下:
private void registerServiceBeans(SetpackagesToScan, BeanDefinitionRegistry registry) { // 创建 Dubbo 扫描类 DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader); BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry); scanner.setBeanNameGenerator(beanNameGenerator); // 扫描被 @Service 注解修饰的类,这里的Service是 org.apache.dubbo.config.annotation.Service scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class)); // 扫描被 @com.alibaba.dubbo.config.annotation.Service 注解修饰的类 scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class)); for (String packageToScan : packagesToScan) { // Registers @Service Bean first scanner.scan(packageToScan); // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not. // 获取所有 @Service 修饰的 Bean的 BeanDefinitionHolder Set beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator); if (!CollectionUtils.isEmpty(beanDefinitionHolders)) { for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) { // 准备注册 ServiceBean的 BeanDefinition registerServiceBean(beanDefinitionHolder, registry, scanner); } ... 日志打印 } else { ... 日志打印 } } }
这里我们可以看到 :
- 首先构建扫描器类 DubboClassPathBeanDefinitionScanner,扫描 被 org.apache.dubbo.config.annotation.Service 注解和 com.alibaba.dubbo.config.annotation.Service 注解修饰的类,并封装成 Set
返回。 - 随后遍历 BeanDefinitionHolder,通过 registerServiceBean(beanDefinitionHolder, registry, scanner); 方法生成 BeanDefinition 并注册到容器中,这里的 BeanDefinition是 ServiceBean的 BeanDefinition。
上面我们看到,ServiceBean的 BeanDefinition 构建交由 registerServiceBean(beanDefinitionHolder, registry, scanner); 来完成,下面我们来看看 registerServiceBean(beanDefinitionHolder, registry, scanner);的具体实现 :
1.3.1 registerServiceBean在 ServiceAnnotationBeanPostProcessor#registerServiceBean 中生成了 ServiceBean 的 BeanDefinition 并注册到容器中。我们这里直接来看 registerServiceBean 的实现,如下:
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
// 获取 提供者类的 Class
Class> beanClass = resolveClass(beanDefinitionHolder);
// 获取 @Service 注解
Annotation service = findServiceAnnotation(beanClass);
// 获取 @Service 注解的属性
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
// 获取暴露的服务接口
Class> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
// 获取 beanName
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// 封装成 ServiceBean BeanDefinition
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
// ServiceBean Bean name
// 获取 ServiceBean 的 beanName ,规则是 ServiceBean:{接口路径}:{版本号}:{分组}
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
// 如果 ServiceBean BeanDefinition 没有注册,则进行注册
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
} else {
// ... 打印日志
}
}
private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class> interfaceClass) {
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
.group(serviceAnnotationAttributes.getString("group"))
.version(serviceAnnotationAttributes.getString("version"));
return builder.build();
}
我们这里需要关注如下代码,该方法构建了 ServiceBean 的 BeanDefinition:
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
其实现如下:
// 该方法返回的是 ServiceBean 的 BeanDefinition
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
AnnotationAttributes serviceAnnotationAttributes,
Class> interfaceClass,
String annotatedServiceBeanName) {
// 1. 创建 BeanDefinition 创建器类
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
// 2. 开始为 BeanDefinition 添加 PropertyValue 属性
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
"interface", "interfaceName", "parameters");
// 2.1 添加Service 注解属性,忽略 ignoreAttributeNames 中的属性
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
// References "ref" property to annotated-@Service Bean
// 2.2 添加 ref 属性。annotatedServiceBeanName是暴露的接口实现类,这里会将其封装为RuntimeBeanReference。
// 如 ProviderServiceImpl 为 Provider Service的实现类,这里会将其封装为 ref : new RuntimeBeanReference("providerServiceImpl")。
addPropertyReference(builder, "ref", annotatedServiceBeanName);
// 2.3 下面也是配置 propertyValue 属性,这里不再继续分析。
....
// 2.4 返回构建的 BeanDefinition
return builder.getBeanDefinition();
}
其中 ServiceBean#ref 保存调用的服务实例, 如下图:
注:
-
关于 RuntimeBeanReference :当我们需要动态注入Bean,并给该Bean的属性注入其他Bean时,比如在Mybatis和Spring的整合中,我们需要动态注入Mapper到spring容器中,而该Mapper如果需要执行SQL语句,还需要持有SqlSessionFactory的引用。但是我们注入时,可能对应的Bean还没有准备好,这时,我们就可以使用RuntimeBeanReference,以保持对实际Bean的引用。在Spring处理依赖关系时,最终会将该引用替换成实际生成的Bean对象。例如:
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
这里我们可以看到 ServiceBean 中包含了 Ref (提供服务的对象实例)、version (服务版本号)、group(服务分组) 等信息,这一步完成 ServiceBean的 BeanDefinition 后,Spring在后续的流程会创建对应的实例对象,Dubbo的服务暴露则是通过 这些ServiceBean 实例来完成。
1.4 总结我们这里总结一下 ServiceAnnotationBeanPostProcessor 的作用:
-
在 Spring容器启动时,会触发 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法,所以在 Spring 容器启动时会触发 ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry 方法。关于 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 方法,如有需要详参 Spring源码分析二:BeanFactoryPostProcessor 的处理
-
ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry 中首先会判断 DubboBootstrapApplicationListener 的 BeanDefinition 是否注册,如果没有,则注册一个 DubboBootstrapApplicationListener 的 BeanDefinition。在 Spring中,一个 Bean如果被创建,首先会创建其 BeanDefinition ,之后再根据BeanDefinition 创建真正的 Bean实例。这里的过程是创建BeanDefinition。
-
随后 ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry 会解析出配置中的 dubbo.scan 配置路径,扫描指定路径下的所有bean,如果 bean被 org.apache.dubbo.config.annotation.Service 和 com.alibaba.dubbo.config.annotation.Service 注解修饰,则会为其创建对应的 ServiceBean 的 BeanDefinition,并注册到容器中。这里需要注意,这里创建的BeanDefinition 代表的类型是 ServiceBean。假设此时 DemoService 被 @Service 注解修饰,这里会创建一个 ServiceBean 的 BeanDefinition,而这个 ServiceBean 中保存了 DemoService 服务暴露的相关信息,如 超时时间、版本号、具体服务实现类等。
上面我们提到了 ServiceAnnotationBeanPostProcessor 中会注册DubboBootstrapApplicationListener 的 BeanDefinition 到容器中。
DubboBootstrapApplicationListener 的作用是监听刷新事件,用来监听Spring容器刷新结束或关闭事件,当Spring容器刷新结束后开始准备暴露dubbo服务,当容器关闭时则准备销毁 dubbo 服务。其实现如下:
public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
implements Ordered {
private final DubboBootstrap dubboBootstrap;
public DubboBootstrapApplicationListener() {
this.dubboBootstrap = DubboBootstrap.getInstance();
}
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
// Springboot 容器刷新结束会发送此事件
if (event instanceof ContextRefreshedEvent) {
// 执行容器刷新
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
// 容器关闭触发
onContextClosedEvent((ContextClosedEvent) event);
}
}
// 启动 Dubbo服务
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
// 销毁 Dubbo服务
private void onContextClosedEvent(ContextClosedEvent event) {
dubboBootstrap.stop();
}
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
}
}
这里我们可以看到 DubboBootstrapApplicationListener 会监听 Spring 事件。
当 Spring容器刷新结束后会发送 ContextRefreshedEvent事件,而DubboBootstrapApplicationListener 接收到该事件后会通过 DubboBootstrap#start 来暴露服务。同理Spring容器销毁时发送 ContextClosedEvent事件,DubboBootstrapApplicationListener 则会通过 DubboBootstrap#stop 来停止 Dubbo 服务的暴露。
四、消费者的启动流程上面我们以服务提供者的视角看了一下 Springboot启动后,Dubbo服务是如何启动的。下面我们来看一看服务消费者是如何引用的Dubbo服务。(我们这里以 @Reference 注解的方式引用 Dubbo服务为例)
对于提供者, Dubbo提供了ServiceAnnotationBeanPostProcessor 类处理 @Service,对于消费者则是提供了 ReferenceAnnotationBeanPostProcessor 来处理 @Reference 注解。
ReferenceAnnotationBeanPostProcessor 的结构如下:
这里需要注意的是 ServiceAnnotationBeanPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,用于注册 BeanDefinition,而 ReferenceAnnotationBeanPostProcessor 实现了 AbstractAnnotationBeanPostProcessor,参与了 Bean的创建过程。
1. ReferenceAnnotationBeanPostProcessor
ReferenceAnnotationBeanPostProcessor 是 Dubbo 提供用来处理 @Reference 注解的后处理器。
ReferenceAnnotationBeanPostProcessor 利用 Bean 后处理器的特性,在每个Bean创建时会判断其是否存在被 @Reference 注解 修饰的属性和方法,如果存在则进行注入。(注入的实例对象是其创建的Dubbo提供者的代理对象。)
关于 Bean 后处理器,如有需要详参:Spring源码分析衍生篇四:后处理器 BeanPostProcessor
下面我们具体来看 ReferenceAnnotationBeanPostProcessor 的逻辑。
1.1 构造函数ReferenceAnnotationBeanPostProcessor 的构造函数如下:
public ReferenceAnnotationBeanPostProcessor() {
// org.apache.dubbo.config.annotation.Reference 和 com.alibaba.dubbo.config.annotation.Reference 注解
super(Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
}
super调用其父类 AbstractAnnotationBeanPostProcessor 的构造函数,如下:
public AbstractAnnotationBeanPostProcessor(Class extends Annotation>... annotationTypes) {
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
this.annotationTypes = annotationTypes;
}
可以看到,这里会将 ReferenceAnnotationBeanPostProcessor#annotationTypes 被赋值为 org.apache.dubbo.config.annotation.Reference 和 com.alibaba.dubbo.config.annotation.Reference。
当 Bean创建时,会遍历其所有的属性和方法,判断是否被 ReferenceAnnotationBeanPostProcessor#annotationTypes 修饰,即是否被 org.apache.dubbo.config.annotation.Reference 和 com.alibaba.dubbo.config.annotation.Reference 修饰。
1.2 ReferenceAnnotationBeanPostProcessor#postProcessPropertyValues
在 Spring 容器中,Bean在创建成功后,会AbstractAutowireCapableBeanFactory#populateBean 方法调用 InstantiationAwareBeanPostProcessor#postProcessProperties 和 InstantiationAwareBeanPostProcessor#postProcessPropertyValues 来填充 Bean的属性。
关于此处的逻辑,如有需要详参 Spring源码分析七:bean的属性注入⑤ - populateBean
而对于 ReferenceAnnotationBeanPostProcessor, InstantiationAwareBeanPostProcessor#postProcessProperties 方法并没有实现,而InstantiationAwareBeanPostProcessor#postProcessPropertyValues 的实现在其父类 AbstractAnnotationBeanPostProcessor中,如下:
// AbstractAnnotationBeanPostProcessor#postProcessPropertyValues
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
// 1. 获取需要依赖注入的元数据信息
Injectionmetadata metadata = findInjectionmetadata(beanName, bean.getClass(), pvs);
try {
// 2. 进行属性注入
metadata.inject(bean, beanName, pvs);
} catch (...) {
... 抛出异常
}
return pvs;
}
这里的逻辑比较简单:
- 挑选出被 ReferenceAnnotationBeanPostProcessor#annotationTypes 修饰的属性或方法,并封装成 Injectionmetadata。
- 调用 Injectionmetadata#inject 来进行属性注入。
下面我们来具体看
1.2.1 AbstractAnnotationBeanPostProcessor#findInjectionmetadataAbstractAnnotationBeanPostProcessor#findInjectionmetadata 方法挑选出被 ReferenceAnnotationBeanPostProcessor#annotationTypes 修饰的属性或方法,并封装成 Injectionmetadata。其实现如下:
private Injectionmetadata findInjectionmetadata(String beanName, Class> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 尝试从缓存中获取
AbstractAnnotationBeanPostProcessor.AnnotatedInjectionmetadata metadata = this.injectionmetadataCache.get(cacheKey);
// 如果需要刷新 : metadata == null || metadata.needsRefresh(clazz)
if (Injectionmetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionmetadataCache) {
metadata = this.injectionmetadataCache.get(cacheKey);
// 进行刷新操作,清除后重新创建
if (Injectionmetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
// 创建 元数据
metadata = buildAnnotatedmetadata(clazz);
this.injectionmetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
... 抛出异常
}
}
}
}
return metadata;
}
通过上面的代码我们可以发现其关键逻辑在于 metadata = buildAnnotatedmetadata(clazz); ,实现如下:
// 创建元数据
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionmetadata buildAnnotatedmetadata(final Class> beanClass) {
// 寻找被指定注解修饰的属性
Collection fieldElements = findFieldAnnotationmetadata(beanClass);
// 寻找被指定注解修饰的方法
Collection methodElements = findAnnotatedMethodmetadata(beanClass);
// 返回
return new AbstractAnnotationBeanPostProcessor.AnnotatedInjectionmetadata(beanClass, fieldElements, methodElements);
}
// 对属性的筛选
private List findFieldAnnotationmetadata(final Class> beanClass) {
final List elements = new linkedList();
// 遍历当前 Bean的所有方法
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
// 获取注解类型
for (Class extends Annotation> annotationType : getAnnotationTypes()) {
// 获取注解属性
AnnotationAttributes attributes = getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);
// 如果属性不为空则说明当前属性被指定注解修饰
if (attributes != null) {
// 属性为静态则直接返回
if (Modifier.isStatic(field.getModifiers())) {
return;
}
// 添加属性集合中
elements.add(new AnnotatedFieldElement(field, attributes));
}
}
}
});
return elements;
}
// 对 方法 的筛选和对属性的基本类型,
private List findAnnotatedMethodmetadata(final Class> beanClass) {
final List elements = new linkedList();
// 遍历当前 Bean的所有方法
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = findBridgedMethod(method);
if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
for (Class extends Annotation> annotationType : getAnnotationTypes()) {
// 筛选被 指定注解修饰的方法
AnnotationAttributes attributes = getAnnotationAttributes(bridgedMethod, annotationType, getEnvironment(), true, true);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
// 筛选非静态
if (Modifier.isStatic(method.getModifiers())) {
return;
}
// 方法至少要有一个入参,这里打日志警告
if (method.getParameterTypes().length == 0) {
... 打印日志
}
// 获取方法表述信息
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
// 保存到集合中
elements.add(new AnnotatedMethodElement(method, pd, attributes));
}
}
}
});
return elements;
}
protected final Class extends Annotation>[] getAnnotationTypes() {
return annotationTypes;
}
上面我们可以看到,如果当前 Bean 有属性或方法被 ReferenceAnnotationBeanPostProcessor#annotationTypes 修饰,则认为当前属性或方法需要被注入。
而 ReferenceAnnotationBeanPostProcessor#annotationTypes 的值则是在构造函数中赋值的 org.apache.dubbo.config.annotation.Reference 和 com.alibaba.dubbo.config.annotation.Reference 。
因此,我们可以简单总结 AbstractAnnotationBeanPostProcessor#findInjectionmetadata的作用是将 Bean 中被 org.apache.dubbo.config.annotation.Reference 和 com.alibaba.dubbo.config.annotation.Reference 修饰的属性或方法筛选出来并封装成 Injectionmetadata。
1.2.2 Injectionmetadata#injectInjectionmetadata#inject 的作用是执行注入操作。其实现如下:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection checkedElements = this.checkedElements;
Collection elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
// 执行元素注入操作,这里会调用 AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement 或 AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement
element.inject(target, beanName, pvs);
}
}
}
这里需要注意:
-
被 @Reference 注解修饰的 属性被封装成AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement 类型。其实现如下:
@Override protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { // 获取注入类型 Class> injectedType = field.getType(); // 获取注入的对象实例 Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this); // 设置权限 ReflectionUtils.makeAccessible(field); // 反射赋值 field.set(bean, injectedObject); } -
被 @Reference 注解修饰的 方法被封装成AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement 类型。其实现如下
@Override protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { // 获取注入类型 Class> injectedType = pd.getPropertyType(); // 获取注入的对象实例 Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this); // 设置权限 ReflectionUtils.makeAccessible(method); // 反射调用 method.invoke(bean, injectedObject); }
上面我们看到,注入的实例是通过 AbstractAnnotationBeanPostProcessor#getInjectedObject来获取,下面我们来看看 其具体实现。
1.2.3 AbstractAnnotationBeanPostProcessor#getInjectedObjectAbstractAnnotationBeanPostProcessor#getInjectedObject 返回了一个服务提供者的代理对象,其实现如下:
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class> injectedType,
Injectionmetadata.InjectedElement injectedElement) throws Exception {
// 获取缓存 key
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
// 尝试从缓存中获取
Object injectedObject = injectedObjectsCache.get(cacheKey);
// 缓存没有命中
if (injectedObject == null) {
// 获取要注入的 Bean
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
// Customized inject-object if necessary
// 放入缓存中
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
return injectedObject;
}
AbstractAnnotationBeanPostProcessor#doGetInjectedBean是一个抽象方法,在 ReferenceAnnotationBeanPostProcessor 中实现了该方法,如下:
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class> injectedType,
Injectionmetadata.InjectedElement injectedElement) throws Exception {
// 以 @Service 注解规则生成的 ServiceBean BeanName
// ServiceBean:com.kingfish.service.ProviderService:1.0.0:spring
String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
// 以 @Reference 注解规则生成的 BeanName :如果指定id,则返回id,否则按照规则:@Reference(属性key=value,...) 接口名 生成
// 如:@Reference(group=spring,version=1.0.0) com.kingfish.service.ProviderService
String referenceBeanName = getReferenceBeanName(attributes, injectedType);
// 为当前引用创建一个 ReferenceBean 对象(如果需要)
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
// ReferenceBean 注册到容器中
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
// 缓存 ReferenceBean
cacheInjectedReferenceBean(referenceBean, injectedElement);
// 创建Dubbo 服务引用服务的代理对象。
return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType);
}
这里可以看到通过 getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType); 方法创建了一个 Dubbo提供者的代理对象并返回。其代理对象创建过程之前文章有过介绍,如有需要详参:Dubbo源码分析:全集整理 (全集中是基于 Dubbo2.7.0,这里是 Dubbo 2.7.5 版本,不过整体逻辑类似)。
以上:内容部分参考
《深度剖析Apache Dubbo 核心技术内幕》
https://blog.csdn.net/lichuangcsdn/article/details/89931460
https://blog.csdn.net/zhaodongchao1992/article/details/103475912
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正



