mirror of
https://github.com/youthlql/JavaYouth.git
synced 2026-03-13 21:33:42 +08:00
1890 lines
76 KiB
Markdown
1890 lines
76 KiB
Markdown
---
|
||
title: 04.Dubbo源码系列V1-Dubbo第四节-Spring与Dubbo整合原理与源码分析
|
||
tags:
|
||
- Dubbo
|
||
- rpc
|
||
categories:
|
||
- rpc
|
||
- Dubbo源码系列v1
|
||
keywords: Dubbo,rpc
|
||
description: Spring与Dubbo整合原理与源码分析
|
||
cover: 'https://npm.elemecdn.com/lql_static@latest/logo/dubbo.png'
|
||
abbrlink: 796f395d
|
||
date: 2021-10-06 13:21:58
|
||
---
|
||
|
||
## 第四节: Spring与Dubbo整合原理与源码分析
|
||
|
||
|
||
|
||
### 笔记更新地址:
|
||
|
||
[https://www.yuque.com/books/share/f2394ae6-381b-4f44-819e-c231b39c1497](https://www.yuque.com/books/share/f2394ae6-381b-4f44-819e-c231b39c1497?#)(密码:kyys) 《Dubbo笔记》
|
||
|
||
|
||
|
||
### 整体架构和流程
|
||
|
||
<img src="https://npm.elemecdn.com/youthlql@1.0.4/rpc/dubbo/v1/04_di_si_jie/Spring整合Dubbo架构图.png"/>
|
||
|
||
#### 处理@Service
|
||
|
||
1. Dubbo的@Service注解Spring的@Service注解重名了,dubbo在2.7版本之后改成了@DubboService注解。
|
||
|
||
> 在Dubbo的文章中如果不是特别说明@Service注解均为Dubbo的注解
|
||
|
||
2. Dubbo在处理@Service注解时会生成两个对象,看上面的图,DemoServiceImpl这个是给Spring容器生成的,意思就是@Service注解兼具了Spring@Service注解的功能。同时@Serivce注解会再生成一个ServiceBean类型的对象,这个对象会做一些事情,比如:将对应的服务类注册到注册中心,将service服务进行分组,分版本,控制超时,权重等等。@Service注解上面写的参数,都是由ServiceBean类型的对象来承接。当调用ServiceBean类型里面的export方法就可以控制服务的注册。
|
||
3. ServiceBean的父类里有一个ref属性,指向这个服务的实现类
|
||
|
||
#### 处理Properties文件
|
||
|
||
```properties
|
||
# 这个会被解析成ApplicationConfig对象
|
||
dubbo.application.name=dubbo-demo-provider1-application
|
||
dubbo.application.logger=log4j
|
||
dubbo.application.timeout=3000
|
||
|
||
|
||
# 这个会被解析成ProtocolConfig
|
||
dubbo.protocols.p1.name=dubbo
|
||
dubbo.protocols.p1.port=20880
|
||
dubbo.protocols.p1.host=0.0.0.0
|
||
|
||
dubbo.protocols.p2.name=dubbo
|
||
dubbo.protocols.p2.port=20881
|
||
dubbo.protocols.p2.host=0.0.0.0
|
||
|
||
|
||
# 这个会被解析成RegistrieConfig
|
||
dubbo.registries.r1.address=zookeeper://127.0.0.1:2181
|
||
dubbo.registries.r1.timeout=3000
|
||
|
||
# 等等
|
||
```
|
||
|
||
这些xxxConfig最后都会赋值给ServiceBean里相应的属性
|
||
|
||
|
||
|
||
|
||
|
||
### 实例解析
|
||
|
||
应用启动类与配置
|
||
|
||
```java
|
||
public class Application {
|
||
public static void main(String[] args) throws Exception {
|
||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
|
||
context.start();
|
||
System.in.read();
|
||
}
|
||
|
||
@Configuration
|
||
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
|
||
@PropertySource("classpath:/spring/dubbo-provider.properties")
|
||
static class ProviderConfiguration {
|
||
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
应用配置类为ProviderConfiguration, 在配置上有两个比较重要的注解
|
||
|
||
1. @PropertySource表示将dubbo-provider.properties中的配置项添加到Spring容器中,可以通过@Value的方式获取到配置项中的值
|
||
2. @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")表示对指定包下的类进行扫描,扫描@Service与@Reference注解,并且进行处理
|
||
|
||
### @EnableDubbo
|
||
|
||
在EnableDubbo注解上,有另外两个注解,也是研究Dubbo最重要的两个注解
|
||
|
||
1. @EnableDubboConfig
|
||
2. @DubboComponentScan
|
||
|
||
```java
|
||
@Target({ElementType.TYPE})
|
||
@Retention(RetentionPolicy.RUNTIME)
|
||
@Inherited
|
||
@Documented
|
||
@Import(DubboConfigConfigurationRegistrar.class)
|
||
public @interface EnableDubboConfig {
|
||
boolean multiple() default true;
|
||
}
|
||
//解析properties文件 ===> xxxConfig
|
||
```
|
||
|
||
|
||
|
||
```java
|
||
@Target(ElementType.TYPE)
|
||
@Retention(RetentionPolicy.RUNTIME)
|
||
@Documented
|
||
@Import(DubboComponentScanRegistrar.class)
|
||
public @interface DubboComponentScan {
|
||
String[] value() default {};
|
||
|
||
String[] basePackages() default {};
|
||
|
||
Class<?>[] basePackageClasses() default {};
|
||
|
||
}
|
||
//解析@Service @Refrence注解
|
||
```
|
||
|
||
|
||
|
||
注意两个注解中对应的@Import注解所导入的类:
|
||
|
||
1. DubboConfigConfigurationRegistrar
|
||
2. DubboComponentScanRegistrar
|
||
|
||
Spring在启动时会解析这两个注解,并且执行对应的Registrar类中的registerBeanDefinitions方法(这是Spring中提供的扩展功能。)
|
||
|
||
|
||
|
||
### DubboConfigConfigurationRegistrar
|
||
|
||
```java
|
||
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
|
||
|
||
@Override
|
||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||
System.out.println("执行DubboConfigConfigurationRegistrar");
|
||
|
||
|
||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
|
||
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
|
||
|
||
boolean multiple = attributes.getBoolean("multiple"); // 拿EnableDubboConfig里的默认值
|
||
|
||
// Single Config Bindings
|
||
registerBeans(registry, DubboConfigConfiguration.Single.class);
|
||
|
||
// 默认为true
|
||
if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
|
||
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
|
||
}
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
|
||
|
||
#### 流程
|
||
|
||
<img src="https://npm.elemecdn.com/youthlql@1.0.4/rpc/dubbo/v1/04_di_si_jie/Spring整合Dubbo只properties文件解析流程.png"/>
|
||
|
||
|
||
|
||
|
||
|
||
Spring启动时,会调用DubboConfigConfigurationRegistrar的registerBeanDefinitions方法,该方法是利用Spring中的AnnotatedBeanDefinitionReader来读取:
|
||
|
||
1. DubboConfigConfiguration.Single.**class**
|
||
2. DubboConfigConfiguration.Multiple.**class**
|
||
|
||
这两个类上的注解。
|
||
|
||
```java
|
||
public class DubboConfigConfiguration {
|
||
|
||
/**
|
||
* Single Dubbo {@link AbstractConfig Config} Bean Binding
|
||
*/
|
||
@EnableDubboConfigBindings({
|
||
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
|
||
})
|
||
public static class Single {
|
||
|
||
}
|
||
|
||
/**
|
||
* Multiple Dubbo {@link AbstractConfig Config} Bean Binding
|
||
*/
|
||
@EnableDubboConfigBindings({
|
||
@EnableDubboConfigBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
|
||
@EnableDubboConfigBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
|
||
})
|
||
public static class Multiple {
|
||
|
||
}
|
||
}
|
||
```
|
||
|
||
大概意思就是什么前缀的注解,对应解析到哪个类的对象里。
|
||
|
||
|
||
|
||
|
||
|
||
这两个类主要用到的就是@EnableDubboConfigBindings注解:
|
||
|
||
```java
|
||
@Target({ElementType.TYPE})
|
||
@Retention(RetentionPolicy.RUNTIME)
|
||
@Documented
|
||
@Import(DubboConfigBindingsRegistrar.class)
|
||
public @interface EnableDubboConfigBindings {
|
||
|
||
/**
|
||
* The value of {@link EnableDubboConfigBindings}
|
||
*
|
||
* @return non-null
|
||
*/
|
||
EnableDubboConfigBinding[] value();
|
||
|
||
}
|
||
```
|
||
|
||
|
||
|
||
@EnableDubboConfigBindings注解上也有一个@Import注解,导入的是DubboConfigBindingsRegistrar.**class**。该类会获取@EnableDubboConfigBindings注解中的value,也就是多个@EnableDubboConfigBinding注解,然后利用DubboConfigBindingRegistrar去处理这些@EnableDubboConfigBinding注解。
|
||
|
||
|
||
|
||
|
||
|
||
#### DubboConfigBindingRegistrar
|
||
|
||
##### 此类总结
|
||
|
||
此类中的主要方法是registerDubboConfigBeans()方法,主要功能就是获取用户所设置的properties文件中的内容,对Properties文件进行解析,根据Properties文件的每个配置项的前缀、参数名、参数值生成对应的BeanDefinition。
|
||
|
||
比如:
|
||
|
||
```java
|
||
dubbo.application.name=dubbo-demo-provider1-application
|
||
dubbo.application.logger=log4j
|
||
```
|
||
|
||
前缀为"dubbo.application"的配置项,会生成一个ApplicationConfig类型的BeanDefinition,并且name和logger属性为对应的值。
|
||
|
||
|
||
|
||
再比如:
|
||
|
||
```java
|
||
dubbo.protocols.p1.name=dubbo
|
||
dubbo.protocols.p1.port=20880
|
||
dubbo.protocols.p1.host=0.0.0.0
|
||
|
||
dubbo.protocols.p2.name=dubbo
|
||
dubbo.protocols.p2.port=20881
|
||
dubbo.protocols.p2.host=0.0.0.0
|
||
```
|
||
|
||
比如前缀为"dubbo.protocols"的配置项,会生成**两**个ProtocolConfig类型的BeanDefinition,两个BeanDefinition的beanName分别为p1和p2。
|
||
|
||
并且还会针对生成的每个BeanDefinition生成一个和它一对一绑定的BeanPostProcessor,类型为DubboConfigBindingBeanPostProcessor.**class**。
|
||
|
||
|
||
|
||
##### 代码注释
|
||
|
||
> 整个类的代码注释
|
||
|
||
```java
|
||
|
||
/**
|
||
* {@link AbstractConfig Dubbo Config} binding Bean registrar
|
||
*
|
||
* @see EnableDubboConfigBinding
|
||
* @see DubboConfigBindingBeanPostProcessor
|
||
* @since 2.5.8
|
||
*/
|
||
public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
|
||
|
||
private final Log log = LogFactory.getLog(getClass());
|
||
|
||
private ConfigurableEnvironment environment;
|
||
|
||
@Override
|
||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||
|
||
System.out.println("执行DubboConfigBindingRegistrar");
|
||
|
||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
|
||
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBinding.class.getName()));
|
||
|
||
registerBeanDefinitions(attributes, registry);
|
||
|
||
}
|
||
|
||
protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
|
||
|
||
// prefix = "dubbo.application"
|
||
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
|
||
|
||
// type = ApplicationConfig.class
|
||
Class<? extends AbstractConfig> configClass = attributes.getClass("type");
|
||
|
||
boolean multiple = attributes.getBoolean("multiple");
|
||
|
||
registerDubboConfigBeans(prefix, configClass, multiple, registry);
|
||
|
||
}
|
||
|
||
private void registerDubboConfigBeans(String prefix,
|
||
Class<? extends AbstractConfig> configClass,
|
||
boolean multiple,
|
||
BeanDefinitionRegistry registry) {
|
||
|
||
// 从properties文件中根据前缀拿对应的配置项,比如根据dubbo.application前缀,
|
||
// 就可以拿到:
|
||
// dubbo.application.name=dubbo-demo-provider-application
|
||
// dubbo.application.logger=log4j
|
||
Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);
|
||
|
||
// 如果没有相关的配置项,则不需要注册BeanDefinition
|
||
if (CollectionUtils.isEmpty(properties)) {
|
||
if (log.isDebugEnabled()) {
|
||
log.debug("There is no property for binding to dubbo config class [" + configClass.getName()
|
||
+ "] within prefix [" + prefix + "]");
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 根据配置项生成beanNames,为什么会有多个?
|
||
// 普通情况一个dubbo.application前缀对应一个ApplicationConfig类型的Bean
|
||
// 特殊情况下,比如dubbo.protocols对应了:
|
||
// dubbo.protocols.p1.name=dubbo
|
||
// dubbo.protocols.p1.port=20880
|
||
// dubbo.protocols.p1.host=0.0.0.0
|
||
|
||
// dubbo.protocols.p2.name=http
|
||
// dubbo.protocols.p2.port=8082
|
||
// dubbo.protocols.p2.host=0.0.0.0
|
||
// 那么就需要对应两个ProtocolConfig类型的Bean,那么就需要两个beanName:p1和p2
|
||
|
||
// 这里就是multiple为true或false的区别,名字的区别,根据multiple用来判断是否从配置项中获取beanName
|
||
// 如果multiple为false,则看有没有配置id属性,如果没有配置则自动生成一个beanName.
|
||
Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
|
||
Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
|
||
|
||
for (String beanName : beanNames) {
|
||
|
||
// 为每个beanName,注册一个空的BeanDefinition
|
||
registerDubboConfigBean(beanName, configClass, registry);
|
||
|
||
// 为每个bean注册一个DubboConfigBindingBeanPostProcessor的Bean后置处理器
|
||
registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
|
||
|
||
}
|
||
|
||
// 注册一个NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
|
||
// 用来把某个XxConfig所对应的beanName设置到name属性中去
|
||
registerDubboConfigBeanCustomizers(registry);
|
||
|
||
}
|
||
|
||
private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,
|
||
BeanDefinitionRegistry registry) {
|
||
|
||
BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
|
||
|
||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||
|
||
registry.registerBeanDefinition(beanName, beanDefinition); // ApplicatinoConfig对象
|
||
|
||
if (log.isInfoEnabled()) {
|
||
log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() +
|
||
"] has been registered.");
|
||
}
|
||
|
||
}
|
||
|
||
private void registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple,
|
||
BeanDefinitionRegistry registry) {
|
||
|
||
// 注册一个DubboConfigBindingBeanPostProcessor的Bean
|
||
// 每个XxConfig的Bean对应一个DubboConfigBindingBeanPostProcessor的Bean
|
||
// 比如,一个ApplicationConfig对应一个DubboConfigBindingBeanPostProcessor,
|
||
// 一个ProtocolConfig也会对应一个DubboConfigBindingBeanPostProcessor
|
||
// 在构造DubboConfigBindingBeanPostProcessor的时候会指定构造方法的值,这样就可以区别开来了
|
||
|
||
Class<?> processorClass = DubboConfigBindingBeanPostProcessor.class;
|
||
|
||
BeanDefinitionBuilder builder = rootBeanDefinition(processorClass);
|
||
|
||
// 真实的前缀,比如dubbo.registries.r2
|
||
String actualPrefix = multiple ? normalizePrefix(prefix) + beanName : prefix;
|
||
|
||
// 添加两个构造方法参数值,所以会调用DubboConfigBindingBeanPostProcessor的两个参数的构造方法
|
||
builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName);
|
||
|
||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||
|
||
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||
|
||
registerWithGeneratedName(beanDefinition, registry);
|
||
|
||
if (log.isInfoEnabled()) {
|
||
log.info("The BeanPostProcessor bean definition [" + processorClass.getName()
|
||
+ "] for dubbo config bean [name : " + beanName + "] has been registered.");
|
||
}
|
||
|
||
}
|
||
|
||
private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) {
|
||
registerInfrastructureBean(registry, BEAN_NAME, NamePropertyDefaultValueDubboConfigBeanCustomizer.class);
|
||
}
|
||
|
||
@Override
|
||
public void setEnvironment(Environment environment) {
|
||
|
||
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
|
||
|
||
this.environment = (ConfigurableEnvironment) environment;
|
||
|
||
}
|
||
|
||
private Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {
|
||
|
||
Set<String> beanNames = new LinkedHashSet<String>();
|
||
|
||
// 比如dubbo.protocols.p1.name=dubbo的propertyName为p1.name
|
||
|
||
for (String propertyName : properties.keySet()) {
|
||
|
||
// propertyName为p1.name
|
||
int index = propertyName.indexOf(".");
|
||
|
||
if (index > 0) {
|
||
|
||
// 截取beanName名字为p1
|
||
String beanName = propertyName.substring(0, index);
|
||
|
||
beanNames.add(beanName);
|
||
}
|
||
|
||
}
|
||
|
||
return beanNames;
|
||
|
||
}
|
||
|
||
private String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass,
|
||
BeanDefinitionRegistry registry) {
|
||
|
||
// 配置了dubbo.application.id=appl,那么appl就是beanName
|
||
String beanName = (String) properties.get("id");
|
||
// 如果beanName为null,则会进入if分支,由spring自动生成一个beanName,比如org.apache.dubbo.config.ApplicationConfig#0
|
||
if (!StringUtils.hasText(beanName)) {
|
||
BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
|
||
beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
|
||
}
|
||
|
||
return beanName;
|
||
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
#### DubboConfigBindingBeanPostProcessor
|
||
|
||
DubboConfigBindingBeanPostProcessor是一个BeanPostProcessor,在Spring启动过程中,会针对所有的Bean对象进行后置加工,但是在DubboConfigBindingBeanPostProcessor中有如下判断:
|
||
|
||
```java
|
||
if (this.beanName.equals(beanName) && bean instanceof AbstractConfig)
|
||
```
|
||
|
||
所以DubboConfigBindingBeanPostProcessor并不会处理Spring容器中的所有Bean,它只会处理上文由Dubbo所生成的Bean对象。
|
||
|
||
并且,在afterPropertiesSet()方法中,会先创建一个DefaultDubboConfigBinder。
|
||
|
||
|
||
|
||
##### 代码注释
|
||
|
||
> 只留了关键性的代码注释,其余省略
|
||
|
||
```java
|
||
/**
|
||
* Dubbo Config Binding {@link BeanPostProcessor}
|
||
*
|
||
* @see EnableDubboConfigBinding
|
||
* @see DubboConfigBindingRegistrar
|
||
* @since 2.5.8
|
||
*/
|
||
|
||
public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, InitializingBean
|
||
, BeanDefinitionRegistryPostProcessor {
|
||
|
||
private final Log log = LogFactory.getLog(getClass());
|
||
|
||
/**
|
||
* The prefix of Configuration Properties
|
||
*/
|
||
private final String prefix;
|
||
|
||
/**
|
||
* Binding Bean Name
|
||
*/
|
||
private final String beanName;
|
||
|
||
private DubboConfigBinder dubboConfigBinder;
|
||
|
||
private ApplicationContext applicationContext;
|
||
|
||
private BeanDefinitionRegistry beanDefinitionRegistry;
|
||
|
||
private boolean ignoreUnknownFields = true;
|
||
|
||
private boolean ignoreInvalidFields = true;
|
||
|
||
private List<DubboConfigBeanCustomizer> configBeanCustomizers = Collections.emptyList();
|
||
|
||
/**
|
||
* @param prefix the prefix of Configuration Properties
|
||
* @param beanName the binding Bean Name
|
||
*/
|
||
public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) {
|
||
Assert.notNull(prefix, "The prefix of Configuration Properties must not be null");
|
||
Assert.notNull(beanName, "The name of bean must not be null");
|
||
this.prefix = prefix;
|
||
this.beanName = beanName;
|
||
}
|
||
|
||
@Override
|
||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||
|
||
|
||
/*
|
||
1.每个XxConfig对应一个BeanPostProcessor,所以每个DubboConfigBindingBeanPostProcessor只处理对应的beanName
|
||
2.阿里这里的代码写的很不好,没必要为每一个Bean都生成一个BeanPostProcessor,多余的加这个if判断,每一个Bean
|
||
都会经过Dubbo生成的BeanPostProcessor,不停的if判断,直到找到自己的BeanPostProcessor。还好Dubbo后面的版本
|
||
把这里改了。
|
||
3.看过Spring源码的应该知道Spring的BeanPostProcessor是所有对象公用的,这种处理就比较好.
|
||
*/
|
||
if (this.beanName.equals(beanName) && bean instanceof AbstractConfig) {
|
||
|
||
AbstractConfig dubboConfig = (AbstractConfig) bean;
|
||
// 从properties文件中获取值,并设置到dubboConfig对象中
|
||
bind(prefix, dubboConfig);
|
||
|
||
// 设置dubboConfig对象的name属性,设置为beanName
|
||
customize(beanName, dubboConfig);
|
||
|
||
}
|
||
|
||
return bean;
|
||
|
||
}
|
||
|
||
private void bind(String prefix, AbstractConfig dubboConfig) {
|
||
|
||
dubboConfigBinder.bind(prefix, dubboConfig);
|
||
|
||
if (log.isInfoEnabled()) {
|
||
log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " +
|
||
"configuration properties : " + prefix);
|
||
}
|
||
}
|
||
|
||
private void customize(String beanName, AbstractConfig dubboConfig) {
|
||
|
||
for (DubboConfigBeanCustomizer customizer : configBeanCustomizers) {
|
||
customizer.customize(beanName, dubboConfig);
|
||
}
|
||
|
||
}
|
||
|
||
@Override
|
||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||
if (bean instanceof AbstractConfig) {
|
||
// 添加别名,id属性的值为别名
|
||
|
||
String id = ((AbstractConfig) bean).getId();
|
||
if (beanDefinitionRegistry != null && beanDefinitionRegistry instanceof DefaultListableBeanFactory) {
|
||
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanDefinitionRegistry;
|
||
if (!StringUtils.isBlank(id) && !factory.hasAlias(beanName, id)) {
|
||
beanDefinitionRegistry.registerAlias(beanName, id);
|
||
}
|
||
}
|
||
}
|
||
return bean;
|
||
}
|
||
|
||
@Override
|
||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||
this.applicationContext = applicationContext;
|
||
}
|
||
|
||
//这里建议看看Spring源码
|
||
@Override
|
||
public void afterPropertiesSet() throws Exception {
|
||
|
||
initDubboConfigBinder(); // 创建DefaultDubboConfigBinder
|
||
|
||
initConfigBeanCustomizers();
|
||
|
||
}
|
||
|
||
private void initDubboConfigBinder() {
|
||
|
||
if (dubboConfigBinder == null) {
|
||
try {
|
||
// 先从Spring容器中获取DubboConfigBinder,默认获取不到
|
||
dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);
|
||
} catch (BeansException ignored) {
|
||
if (log.isDebugEnabled()) {
|
||
log.debug("DubboConfigBinder Bean can't be found in ApplicationContext.");
|
||
}
|
||
|
||
// Use Default implementation
|
||
// 生成一个默认的
|
||
dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());
|
||
}
|
||
}
|
||
|
||
dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
|
||
dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);
|
||
|
||
}
|
||
|
||
private void initConfigBeanCustomizers() {
|
||
|
||
// 得到之前创建了的NamePropertyDefaultValueDubboConfigBeanCustomizer
|
||
Collection<DubboConfigBeanCustomizer> configBeanCustomizers =
|
||
beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values();
|
||
|
||
this.configBeanCustomizers = new ArrayList<>(configBeanCustomizers);
|
||
|
||
AnnotationAwareOrderComparator.sort(this.configBeanCustomizers);
|
||
}
|
||
|
||
/**
|
||
* Create {@link DubboConfigBinder} instance.
|
||
*
|
||
* @param environment
|
||
* @return {@link DefaultDubboConfigBinder}
|
||
*/
|
||
protected DubboConfigBinder createDubboConfigBinder(Environment environment) {
|
||
DefaultDubboConfigBinder defaultDubboConfigBinder = new DefaultDubboConfigBinder();
|
||
defaultDubboConfigBinder.setEnvironment(environment);
|
||
return defaultDubboConfigBinder;
|
||
}
|
||
|
||
@Override
|
||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||
if (this.beanDefinitionRegistry == null) {
|
||
this.beanDefinitionRegistry = registry;
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||
//do nothing here
|
||
}
|
||
}
|
||
```
|
||
|
||
#### DefaultDubboConfigBinder
|
||
|
||
当某个AbstractConfig类型的Bean,在经过DubboConfigBindingBeanPostProcessor处理时,此时Bean对象中的属性是没有值的,会利用DefaultDubboConfigBinder进行赋值。底层就是利用Spring中的DataBinder技术,结合properties文件对对应的属性进行赋值。
|
||
|
||
|
||
|
||
对应一个AbstractConfig类型(针对的其实是子类,比如ApplicationConfig、RegistryConfig)的Bean,每个类都有一些属性,而properties文件是一个key-value对,所以实际上DataBinder就是将属性名和properties文件中的key进行匹配,如果匹配成功,则把value赋值给属性。具体DataBinder技术是如何工作的,请自行学习(不难)。
|
||
|
||
|
||
|
||
举个例子:
|
||
|
||
```java
|
||
dubbo.application.name=dubbo-demo-provider1-application
|
||
dubbo.application.logger=log4j
|
||
```
|
||
|
||
|
||
|
||
对于此配置,它对应ApplicationConfig对象(beanName是自动生成的),所以最终ApplicationConfig对象的name属性的值为“dubbo-demo-provider1-application”,logger属性的值为“log4j”。
|
||
|
||
|
||
|
||
对于
|
||
|
||
```java
|
||
dubbo.protocols.p1.name=dubbo
|
||
dubbo.protocols.p1.port=20880
|
||
dubbo.protocols.p1.host=0.0.0.0
|
||
```
|
||
|
||
|
||
|
||
它对应ProtocolConfig对象(beanName为p1),所以最终ProtocolConfig对象的name属性的值为“dubbo”,port属性的值为20880,host属性的值为“0.0.0.0”。
|
||
|
||
|
||
|
||
这样就完成了对properties文件的解析。
|
||
|
||
|
||
|
||
```java
|
||
public class DefaultDubboConfigBinder extends AbstractDubboConfigBinder {
|
||
|
||
@Override
|
||
public <C extends AbstractConfig> void bind(String prefix, C dubboConfig) {
|
||
DataBinder dataBinder = new DataBinder(dubboConfig);
|
||
// Set ignored*
|
||
dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());
|
||
dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());
|
||
// Get properties under specified prefix from PropertySources
|
||
// getPropertySources()会拿到由@PropertySource注入进来的properties文件中的内容
|
||
// 同时还包括当前java的所有环境变量,包括手动通过-D添加的配置
|
||
|
||
Map<String, Object> properties = getSubProperties(getPropertySources(), prefix);
|
||
// Convert Map to MutablePropertyValues
|
||
MutablePropertyValues propertyValues = new MutablePropertyValues(properties);
|
||
// Bind
|
||
dataBinder.bind(propertyValues);
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
#### 总结
|
||
|
||
DubboConfigConfigurationRegistrar的主要作用就是对propties文件进行解析并根据不同的配置项项生成对应类型的Bean对象。
|
||
|
||
|
||
|
||
|
||
|
||
### DubboComponentScanRegistrar
|
||
|
||
DubboConfigConfigurationRegistrar的作用是向Spring容器中注册两个Bean:
|
||
|
||
1. ServiceAnnotationBeanPostProcessor
|
||
2. ReferenceAnnotationBeanPostProcessor
|
||
|
||
|
||
|
||
#### 代码注释
|
||
|
||
> 部分代码注释
|
||
|
||
```java
|
||
/**
|
||
* Dubbo {@link DubboComponentScan} Bean Registrar
|
||
*
|
||
* @see Service
|
||
* @see DubboComponentScan
|
||
* @see ImportBeanDefinitionRegistrar
|
||
* @see ServiceAnnotationBeanPostProcessor
|
||
* @see ReferenceAnnotationBeanPostProcessor
|
||
* @since 2.5.7
|
||
*/
|
||
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
|
||
|
||
|
||
@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方法
|
||
// 在这个过程中会按照@Reference注解的信息去生成一个RefrenceBean对象
|
||
registerReferenceAnnotationBeanPostProcessor(registry);
|
||
|
||
}
|
||
|
||
/**
|
||
* Registers {@link ServiceAnnotationBeanPostProcessor}
|
||
*
|
||
* @param packagesToScan packages to scan without resolving placeholders
|
||
* @param registry {@link BeanDefinitionRegistry}
|
||
* @since 2.5.8
|
||
*/
|
||
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);
|
||
|
||
}
|
||
|
||
/**
|
||
* Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory}
|
||
*
|
||
* @param registry {@link BeanDefinitionRegistry}
|
||
*/
|
||
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
|
||
|
||
// Register @Reference Annotation Bean Processor
|
||
// 注册一个ReferenceAnnotationBeanPostProcessor做为bean,ReferenceAnnotationBeanPostProcessor是一个BeanPostProcessor
|
||
BeanRegistrar.registerInfrastructureBean(registry,
|
||
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
|
||
|
||
}
|
||
//省略...
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
#### ServiceAnnotationBeanPostProcessor
|
||
|
||
> 主要就是处理@Service注解
|
||
|
||
<img src="https://npm.elemecdn.com/youthlql@1.0.4/rpc/dubbo/v1/04_di_si_jie/@Service注解处理流程.png"/>
|
||
|
||
|
||
|
||
|
||
|
||
ServiceAnnotationBeanPostProcessor是一个BeanDefinitionRegistryPostProcessor,是用来注册BeanDefinition的。这个类的名字起的不太好。
|
||
|
||
|
||
|
||
它的主要作用是扫描Dubbo的@Service注解,一旦扫描到某个@Service注解就把它以及被它注解的类当做一个Dubbo服务,进行**服务导出**。
|
||
|
||
|
||
|
||
##### DubboClassPathBeanDefinitionScanner
|
||
|
||
DubboClassPathBeanDefinitionScanner是所Dubbo自定义的扫描器,继承了Spring中的ClassPathBeanDefinitionScanner了。
|
||
|
||
|
||
|
||
DubboClassPathBeanDefinitionScanner相对于ClassPathBeanDefinitionScanner并没有做太多的改变,只是把useDefaultFilters设置为了false,主要是因为Dubbo中的@Service注解是Dubbo自定义的,在这个注解上并没有用@Component注解(因为Dubbo不是一定要结合Spring才能用),所以为了能利用Spring的扫描逻辑,需要把useDefaultFilters设置为false。
|
||
|
||
|
||
|
||
每扫描到一个@Service注解,就会得到一个BeanDefinition,这个BeanDefinition的beanClass属性就是具体的服务实现类。
|
||
|
||
|
||
|
||
但,如果仅仅只是这样,这只是得到了一个Spring中的Bean,对于Dubbo来说此时得到的Bean是一个**服务**,并且,还需要解析@Service注解的配置信息,因为这些都是服务的参数信息,所以在扫描完了之后,会针对所得到的每个BeanDefinition,都会**额外**的再生成一个**ServiceBean**类型的Bean对象。
|
||
|
||
|
||
|
||
##### ServiceBean
|
||
|
||
ServiceBean表示一个Dubbo服务,它有一些参数,比如:
|
||
|
||
1. **ref,表示服务的具体实现类**
|
||
2. **interface,表示服务的接口**
|
||
3. **parameters,表示服务的参数(@Service注解中所配置的信息)**
|
||
4. **application,表示服务所属的应用**
|
||
5. **protocols,表示服务所使用的协议**
|
||
6. **registries,表示服务所要注册的注册中心**
|
||
|
||
**所以在扫描到一个@Service注解后,其实会得到两个Bean:**
|
||
|
||
1. 一个就是服务实现类本身一个Bean对象
|
||
2. 一个就是对应的ServiceBean类型的一个Bean对象
|
||
|
||
|
||
|
||
并且需要注意的是,ServiceBean实现了ApplicationListener接口,所以当Spring启动完成后会触发onApplicationEvent()方法的调用,而在这个方法内会调用**export()**,这个方法就是**服务导出的入口方法**。
|
||
|
||
|
||
|
||
> 关于RuntimeBeanReference参考[https://www.yuque.com/renyong-jmovm/ufz328/gbwvk7](https://www.yuque.com/renyong-jmovm/ufz328/gbwvk7)。
|
||
|
||
|
||
|
||
##### 代码注释
|
||
|
||
> 部分代码注释
|
||
|
||
```java
|
||
/**
|
||
* {@link Service} Annotation
|
||
* {@link BeanDefinitionRegistryPostProcessor Bean Definition Registry Post Processor}
|
||
*
|
||
* @since 2.5.8
|
||
*/
|
||
public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
|
||
ResourceLoaderAware, BeanClassLoaderAware {
|
||
|
||
|
||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||
|
||
private final Set<String> packagesToScan;
|
||
|
||
private Environment environment;
|
||
|
||
private ResourceLoader resourceLoader;
|
||
|
||
private ClassLoader classLoader;
|
||
|
||
public ServiceAnnotationBeanPostProcessor(String... packagesToScan) {
|
||
this(Arrays.asList(packagesToScan));
|
||
}
|
||
|
||
public ServiceAnnotationBeanPostProcessor(Collection<String> packagesToScan) {
|
||
this(new LinkedHashSet<>(packagesToScan));
|
||
}
|
||
|
||
public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) {
|
||
this.packagesToScan = packagesToScan;
|
||
}
|
||
|
||
@Override
|
||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||
|
||
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
|
||
|
||
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
|
||
// 扫描包,进行Bean注册
|
||
registerServiceBeans(resolvedPackagesToScan, registry);
|
||
} else {
|
||
if (logger.isWarnEnabled()) {
|
||
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* Registers Beans whose classes was annotated {@link Service}
|
||
*
|
||
* @param packagesToScan The base packages to scan
|
||
* @param registry {@link BeanDefinitionRegistry}
|
||
*/
|
||
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
|
||
|
||
DubboClassPathBeanDefinitionScanner scanner =
|
||
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
|
||
|
||
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
|
||
|
||
scanner.setBeanNameGenerator(beanNameGenerator);
|
||
|
||
// 扫描被Service注解标注的类,先成为Spring里的bean,也就是dubbo服务的实现类
|
||
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
|
||
|
||
/**
|
||
* Add the compatibility for legacy Dubbo's @Service
|
||
*
|
||
* The issue : https://github.com/apache/dubbo/issues/4330
|
||
* @since 2.7.3
|
||
*/
|
||
scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class));
|
||
|
||
for (String packageToScan : packagesToScan) {
|
||
|
||
// Registers @Service Bean first
|
||
// 扫描Dubbo自定义的@Service注解
|
||
scanner.scan(packageToScan);
|
||
|
||
// 查找被@Service注解的类的BeanDefinition(无论这个类有没有被@ComponentScan注解标注了)
|
||
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
|
||
// beanDefinitionHolders装的就是dubbo服务的实现类,存在了Spring容器里
|
||
Set<BeanDefinitionHolder> beanDefinitionHolders =
|
||
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
|
||
|
||
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
|
||
|
||
// 扫描到BeanDefinition开始处理它,准备生成ServiceBean
|
||
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
|
||
registerServiceBean(beanDefinitionHolder, registry, scanner);
|
||
}
|
||
|
||
if (logger.isInfoEnabled()) {
|
||
logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " +
|
||
beanDefinitionHolders +
|
||
" } were scanned under package[" + packageToScan + "]");
|
||
}
|
||
|
||
} else {
|
||
|
||
if (logger.isWarnEnabled()) {
|
||
logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
|
||
+ packageToScan + "]");
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* Registers {@link ServiceBean} from new annotated {@link Service} {@link BeanDefinition}
|
||
*
|
||
* @param beanDefinitionHolder
|
||
* @param registry
|
||
* @param scanner
|
||
* @see ServiceBean
|
||
* @see BeanDefinition
|
||
*/
|
||
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
|
||
DubboClassPathBeanDefinitionScanner scanner) {
|
||
// 服务实现类
|
||
Class<?> beanClass = resolveClass(beanDefinitionHolder);
|
||
// @Service注解
|
||
Annotation service = findServiceAnnotation(beanClass);
|
||
|
||
/**
|
||
* The {@link AnnotationAttributes} of @Service annotation
|
||
*/
|
||
// @Service注解上的信息
|
||
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
|
||
|
||
// 服务实现类对应的接口
|
||
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
|
||
// 服务实现类对应的bean的名字,比如:demoServiceImpl
|
||
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
|
||
|
||
// 生成一个ServiceBean
|
||
AbstractBeanDefinition serviceBeanDefinition =
|
||
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
|
||
|
||
// ServiceBean Bean name
|
||
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
|
||
|
||
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
|
||
|
||
// 把ServiceBean注册进去,对应的beanName为ServiceBean:org.apache.dubbo.demo.DemoService
|
||
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
|
||
|
||
if (logger.isInfoEnabled()) {
|
||
logger.info("The BeanDefinition[" + serviceBeanDefinition +
|
||
"] of ServiceBean has been registered with name : " + beanName);
|
||
}
|
||
|
||
} else {
|
||
|
||
if (logger.isWarnEnabled()) {
|
||
logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition +
|
||
"] of ServiceBean[ bean name : " + beanName +
|
||
"] was be found , Did @DubboComponentScan scan to same package in many times?");
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* Generates the bean name of {@link ServiceBean}
|
||
*
|
||
* @param serviceAnnotationAttributes
|
||
* @param interfaceClass the class of interface annotated {@link Service}
|
||
* @return ServiceBean@interfaceClassName#annotatedServiceBeanName
|
||
* @since 2.7.3
|
||
*/
|
||
private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass) {
|
||
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
|
||
.group(serviceAnnotationAttributes.getString("group"))
|
||
.version(serviceAnnotationAttributes.getString("version"));
|
||
return builder.build();
|
||
}
|
||
|
||
|
||
/**
|
||
* Build the {@link AbstractBeanDefinition Bean Definition}
|
||
*
|
||
* @param serviceAnnotation
|
||
* @param serviceAnnotationAttributes
|
||
* @param interfaceClass
|
||
* @param annotatedServiceBeanName
|
||
* @return
|
||
* @since 2.7.3
|
||
*/
|
||
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
|
||
AnnotationAttributes serviceAnnotationAttributes,
|
||
Class<?> interfaceClass,
|
||
String annotatedServiceBeanName) {
|
||
// 生成一个ServiceBean对应的BeanDefinition
|
||
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
|
||
|
||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||
|
||
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
|
||
|
||
|
||
/*
|
||
1.先忽略这些比较特殊的属性,为什么要忽略呢?
|
||
2.其它不忽略的属性,在@Service注解上写的是字符串形式,ServiceBean里也是字符串类型,所以可以直接赋值
|
||
3.下面的这些特殊属性,比如protocol,在注解上写的是@Service(protocol="p1")这样的字符串,但是在ServiceBean里
|
||
对应的是ProtocolConfig类型的属性,不可能把字符串赋值给这类型。所以先忽略,后面可以看到单独处理了
|
||
*/
|
||
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
|
||
"interface", "interfaceName", "parameters");
|
||
|
||
// 把@Service注解中的参数值赋值给ServiceBean的属性
|
||
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
|
||
|
||
// References "ref" property to annotated-@Service Bean
|
||
// ref属性赋值为另外一个bean, 对应的就是被@Service注解的服务实现类对应的bean
|
||
addPropertyReference(builder, "ref", annotatedServiceBeanName);
|
||
// Set interface
|
||
builder.addPropertyValue("interface", interfaceClass.getName());
|
||
// Convert parameters into map
|
||
builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
|
||
|
||
// 配置了methods属性,则给ServiceBean对应的methods属性赋值
|
||
// Add methods parameters
|
||
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
|
||
if (!methodConfigs.isEmpty()) {
|
||
builder.addPropertyValue("methods", methodConfigs);
|
||
}
|
||
|
||
/**
|
||
* Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
|
||
*/
|
||
String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
|
||
if (StringUtils.hasText(providerConfigBeanName)) {
|
||
addPropertyReference(builder, "provider", providerConfigBeanName);
|
||
}
|
||
|
||
/**
|
||
* Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
|
||
*/
|
||
String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
|
||
if (StringUtils.hasText(monitorConfigBeanName)) {
|
||
addPropertyReference(builder, "monitor", monitorConfigBeanName);
|
||
}
|
||
|
||
/**
|
||
* Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
|
||
*/
|
||
String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
|
||
if (StringUtils.hasText(applicationConfigBeanName)) {
|
||
addPropertyReference(builder, "application", applicationConfigBeanName);
|
||
}
|
||
|
||
/**
|
||
* Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
|
||
*/
|
||
String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
|
||
if (StringUtils.hasText(moduleConfigBeanName)) {
|
||
addPropertyReference(builder, "module", moduleConfigBeanName);
|
||
}
|
||
|
||
|
||
/**
|
||
* Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
|
||
* 获取注解上配置的注册中心的beanName
|
||
*/
|
||
String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry");
|
||
|
||
List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
|
||
|
||
if (!registryRuntimeBeanReferences.isEmpty()) {
|
||
builder.addPropertyValue("registries", registryRuntimeBeanReferences);
|
||
}
|
||
|
||
/**
|
||
* Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
|
||
*/
|
||
String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol");
|
||
|
||
List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
|
||
|
||
if (!protocolRuntimeBeanReferences.isEmpty()) {
|
||
builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
|
||
}
|
||
|
||
return builder.getBeanDefinition();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
```
|
||
|
||
#### ReferenceAnnotationBeanPostProcessor
|
||
|
||
> 处理@Reference注解
|
||
|
||
<img src="https://npm.elemecdn.com/youthlql@1.0.4/rpc/dubbo/v1/04_di_si_jie/@Reference注解处理流程.png"/>
|
||
|
||
##### 总结
|
||
|
||
|
||
|
||
ReferenceAnnotationBeanPostProcessor是处理@Reference注解的。
|
||
|
||
|
||
|
||
ReferenceAnnotationBeanPostProcessor的父类是AnnotationInjectedBeanPostProcessor,是一个InstantiationAwareBeanPostProcessorAdapter,是一个BeanPostProcessor。
|
||
|
||
|
||
|
||
Spring在对Bean进行依赖注入时会调用AnnotationInjectedBeanPostProcessor的postProcessPropertyValues()方法来给某个Bean按照ReferenceAnnotationBeanPostProcessor的逻辑进行依赖注入。
|
||
|
||
|
||
|
||
在注入之前会查找注入点,被@Reference注解的属性或方法都是注入点。
|
||
|
||
|
||
|
||
针对某个Bean找到所有注入点之后,就会进行注入了,注入就是给属性或给set方法赋值,但是在赋值之前得先得到一个值,此时就会调用ReferenceAnnotationBeanPostProcessor的**doGetInjectedBean()**方法来得到一个对象,而这个对象的构造就比较复杂了,因为对于Dubbo来说,注入给某个属性的应该是当前这个**属性所对应的服务接口的代理对象**。
|
||
|
||
|
||
|
||
但是在生成这个代理对象之前,还要考虑问题:
|
||
|
||
1. 当前所需要引入的这个服务,是不是在本地就存在(就是当前项目)?不存在则要把按Dubbo的逻辑生成一个代理对象
|
||
2. 当前所需要引入的这个服务,是不是已经被引入过了(是不是已经生成过代理对象了),如果是应该是不用再重复去生成了。
|
||
|
||
|
||
|
||
**首先如何判断当前所引入的服务是本地的一个服务(就是当前应用自己所提供的服务)。**
|
||
|
||
我们前面提到,Dubbo通过@Service来提供一个服务,并且会生成两个Bean:
|
||
|
||
1. 一个服务实现类本身Bean
|
||
2. 一个ServiceBean类型的Bean,这个Bean的名字是这么生成的:
|
||
|
||
```java
|
||
private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass) {
|
||
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
|
||
.group(serviceAnnotationAttributes.getString("group"))
|
||
.version(serviceAnnotationAttributes.getString("version"));
|
||
return builder.build();
|
||
}
|
||
```
|
||
|
||
|
||
|
||
是通过接口类型+group+version来作为ServiceBean类型Bean的名字的。
|
||
|
||
```java
|
||
ServiceBean:org.apache.dubbo.demo.DemoService:group:version
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
所以现在对于服务引入,也应该提前根据@Reference注解中的信息和属性接口类型去判断一下当前Spring容器中是否存在对应的ServiceBean对象,如果存在则直接取出ServiceBean对象的ref属性所对应的对象,作为要注入的结果。
|
||
|
||
|
||
|
||
**然后如何判断当前所引入的这个服务是否已经被引入过了****(是不是已经生成过代理对象了)。**
|
||
|
||
这就需要在第一次引入某个服务后(生成代理对象后)进行缓存(记录一下)。Dubbo中是这么做的:
|
||
|
||
1. 首先根据@Reference注解的所有信息+属性接口类型生成一个**字符串**
|
||
2. 然后@Reference注解的所有信息+属性接口类型生成一个ReferenceBean对象(**ReferenceBean对象中的get方法可以得到一个Dubbo生成的代理对象,可以理解为服务引入的入口方法**)
|
||
3. 把字符串作为beanName,ReferenceBean对象作为bean注册到Spring容器中,同时也会放入**referenceBeanCache**中。
|
||
|
||
|
||
|
||
|
||
|
||
有了这些逻辑,@Reference注解服务引入的过程是这样的:
|
||
|
||
1. 得到当前所引入服务对应的ServiceBean的beanName(源码中叫referencedBeanName)
|
||
2. 根据@Reference注解的所有信息+属性接口类型得到一个referenceBeanName
|
||
3. 根据referenceBeanName从**referenceBeanCach**e获取对应的ReferenceBean,如果没有则创建一个ReferenceBean
|
||
4. 根据referencedBeanName(ServiceBean的beanName)判断Spring容器中是否存在该bean,如果存在则给ref属性所对应的bean取一个别名,别名为referenceBeanName。
|
||
|
||
1. 如果Spring容器中不存在referencedBeanName对应的bean,则判断容器中是否存在referenceBeanName所对应的Bean,如果不存在则将创建出来的ReferenceBean注册到Spring容器中(**此处这么做就支持了可以通过@Autowired注解也可以使用服务了,****ReferenceBean是一个FactoryBean**)
|
||
|
||
5. 如果referencedBeanName存在对应的Bean,则额外生成一个代理对象,代理对象的InvocationHandler会缓存在**localReferenceBeanInvocationHandlerCache中,这样如果引入的是同一个服务,并且这个服务在本地,**
|
||
6. 如果referencedBeanName不存在对应的Bean,则直接调用ReferenceBean的get()方法得到一个代理对象
|
||
|
||
|
||
|
||
##### AnnotationInjectedBeanPostProcessor代码注释
|
||
|
||
> 这个类是Spring的类
|
||
|
||
```java
|
||
public AnnotationInjectedBeanPostProcessor(Class<? extends Annotation>... annotationTypes) {
|
||
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
|
||
this.annotationTypes = annotationTypes;
|
||
}
|
||
|
||
@Override
|
||
public PropertyValues postProcessPropertyValues(
|
||
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
|
||
|
||
// 寻找需要注入的属性(被@Reference标注的Field),也就是寻找注入点
|
||
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
|
||
try {
|
||
metadata.inject(bean, beanName, pvs);
|
||
} catch (BeanCreationException ex) {
|
||
throw ex;
|
||
} catch (Throwable ex) {
|
||
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
|
||
+ " dependencies is failed", ex);
|
||
}
|
||
return pvs;
|
||
}
|
||
|
||
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.
|
||
AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
|
||
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) {
|
||
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
|
||
"] for annotation metadata: could not find class that it depends on", err);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return metadata;
|
||
}
|
||
|
||
private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
|
||
|
||
// 哪些Filed上有@Reference注解
|
||
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
|
||
// 哪些方法上有@Reference注解
|
||
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
|
||
// 返回的是Dubbo定义的AnnotatedInjectionMetadata,接下来就会使用这个类去进行属性注入
|
||
return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
|
||
|
||
}
|
||
|
||
/**
|
||
* {@link Annotation Annotated} {@link InjectionMetadata} implementation
|
||
*/
|
||
private class AnnotatedInjectionMetadata extends InjectionMetadata {
|
||
|
||
private final Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements;
|
||
|
||
private final Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements;
|
||
|
||
public AnnotatedInjectionMetadata(Class<?> targetClass, Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements,
|
||
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements) {
|
||
super(targetClass, combine(fieldElements, methodElements));
|
||
this.fieldElements = fieldElements;
|
||
this.methodElements = methodElements;
|
||
}
|
||
|
||
public Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> getFieldElements() {
|
||
return fieldElements;
|
||
}
|
||
|
||
public Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> getMethodElements() {
|
||
return methodElements;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* {@link Annotation Annotated} {@link Method} {@link InjectionMetadata.InjectedElement}
|
||
*/
|
||
private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement {
|
||
|
||
private final Method method;
|
||
|
||
private final AnnotationAttributes attributes;
|
||
|
||
private volatile Object object;
|
||
|
||
protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes) {
|
||
super(method, pd);
|
||
this.method = method;
|
||
this.attributes = attributes;
|
||
}
|
||
|
||
@Override
|
||
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
|
||
|
||
// set方法对应的属性的类型
|
||
Class<?> injectedType = pd.getPropertyType();
|
||
|
||
// 从Spring容器中获取一个Bean(注意,这个方法内部会生成Bean而且会缓存,就像Spring中的getBean一样)
|
||
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
|
||
|
||
ReflectionUtils.makeAccessible(method);
|
||
|
||
// 调用set方法
|
||
method.invoke(bean, injectedObject);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* {@link Annotation Annotated} {@link Field} {@link InjectionMetadata.InjectedElement}
|
||
*/
|
||
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
|
||
|
||
private final Field field;
|
||
|
||
private final AnnotationAttributes attributes;
|
||
|
||
private volatile Object bean;
|
||
|
||
protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes) {
|
||
super(field, null);
|
||
this.field = field;
|
||
this.attributes = attributes;
|
||
}
|
||
|
||
@Override
|
||
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
|
||
// 给bean对象进行属性赋值
|
||
|
||
Class<?> injectedType = field.getType();
|
||
|
||
// 获取对象,然后进行注入
|
||
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
|
||
|
||
ReflectionUtils.makeAccessible(field);
|
||
|
||
// 字段赋值,injectedObject就是值
|
||
field.set(bean, injectedObject);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
|
||
InjectionMetadata.InjectedElement injectedElement) throws Exception {
|
||
// ServiceBean:org.apache.dubbo.demo.DemoService#source=private org.apache.dubbo.demo.DemoService org.apache.dubbo.demo.consumer.comp.DemoServiceComponent.demoService#attributes={parameters=[Ljava.lang.String;@42e25b0b}
|
||
// 哪个Service应用了哪个类型的服务,通过什么方式引入的
|
||
// cacheKey很鸡肋,属性名不一样的时候,cacheKey不一样,导致不能缓存, 在一个Service中@Reference两次同一个服务缓存不到
|
||
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
|
||
|
||
|
||
Object injectedObject = injectedObjectsCache.get(cacheKey);
|
||
|
||
if (injectedObject == null) {
|
||
// // 这里会调用子类的方法生成Bean,这里的子类指的就是ReferenceAnnotationBeanPostProcessor
|
||
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
|
||
|
||
// Customized inject-object if necessary
|
||
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
|
||
}
|
||
|
||
return injectedObject;
|
||
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
##### ReferenceAnnotationBeanPostProcessor代码注释
|
||
|
||
> 部分注释
|
||
|
||
```java
|
||
/**
|
||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
|
||
* that Consumer service {@link Reference} annotated fields
|
||
*
|
||
* @since 2.5.7
|
||
*/
|
||
public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor implements
|
||
ApplicationContextAware, ApplicationListener {
|
||
|
||
/**
|
||
* The bean name of {@link ReferenceAnnotationBeanPostProcessor}
|
||
*/
|
||
public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";
|
||
|
||
/**
|
||
* Cache size
|
||
*/
|
||
private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);
|
||
|
||
private final ConcurrentMap<String, ReferenceBean<?>> referenceBeanCache =
|
||
new ConcurrentHashMap<>(CACHE_SIZE);
|
||
|
||
private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> localReferenceBeanInvocationHandlerCache =
|
||
new ConcurrentHashMap<>(CACHE_SIZE);
|
||
|
||
private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanCache =
|
||
new ConcurrentHashMap<>(CACHE_SIZE);
|
||
|
||
private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanCache =
|
||
new ConcurrentHashMap<>(CACHE_SIZE);
|
||
|
||
private ApplicationContext applicationContext;
|
||
|
||
/**
|
||
* To support the legacy annotation that is @com.alibaba.dubbo.config.annotation.Reference since 2.7.3
|
||
*/
|
||
public ReferenceAnnotationBeanPostProcessor() {
|
||
////调用AnnotationInjectedBeanPostProcessor的构造
|
||
super(Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
|
||
}
|
||
|
||
/**
|
||
* Gets all beans of {@link ReferenceBean}
|
||
*
|
||
* @return non-null read-only {@link Collection}
|
||
* @since 2.5.9
|
||
*/
|
||
public Collection<ReferenceBean<?>> getReferenceBeans() {
|
||
return referenceBeanCache.values();
|
||
}
|
||
|
||
/**
|
||
* Get {@link ReferenceBean} {@link Map} in injected field.
|
||
*
|
||
* @return non-null {@link Map}
|
||
* @since 2.5.11
|
||
*/
|
||
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
|
||
return Collections.unmodifiableMap(injectedFieldReferenceBeanCache);
|
||
}
|
||
|
||
/**
|
||
* Get {@link ReferenceBean} {@link Map} in injected method.
|
||
*
|
||
* @return non-null {@link Map}
|
||
* @since 2.5.11
|
||
*/
|
||
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
|
||
return Collections.unmodifiableMap(injectedMethodReferenceBeanCache);
|
||
}
|
||
|
||
// 该方法得到的对象会赋值给@ReferenceBean注解的属性
|
||
//
|
||
@Override
|
||
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
|
||
InjectionMetadata.InjectedElement injectedElement) throws Exception {
|
||
|
||
|
||
// 按ServiceBean的beanName生成规则来生成referencedBeanName, 规则为ServiceBean:interfaceClassName:version:group
|
||
String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
|
||
|
||
/*
|
||
1.相当于根据@Reference注解的信息(包括注解括号里的参数)按照toString的逻辑,生成referenceBeanName,这个东西是作为缓存的key
|
||
实际上是进行了一些字符串的转换啥的,不用关心
|
||
2.注意referencedBeanName和referenceBeanName的区别【一个有d字母,一个没有】。referencedBeanName是ServiceBean的
|
||
名字。referenceBeanName是ReferenceBean的名字
|
||
*/
|
||
String referenceBeanName = getReferenceBeanName(attributes, injectedType);
|
||
|
||
// 生成一个ReferenceBean对象
|
||
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
|
||
|
||
// 把referenceBean添加到Spring容器中去
|
||
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
|
||
|
||
//缓存注入点,不重要
|
||
cacheInjectedReferenceBean(referenceBean, injectedElement);
|
||
|
||
// 创建一个代理对象,Service中的属性被注入的就是这个代理对象
|
||
// 内部会调用referenceBean.get();
|
||
return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType);
|
||
}
|
||
|
||
/**
|
||
* Register an instance of {@link ReferenceBean} as a Spring Bean
|
||
*
|
||
* @param referencedBeanName The name of bean that annotated Dubbo's {@link Service @Service} in the Spring {@link ApplicationContext}
|
||
* @param referenceBean the instance of {@link ReferenceBean} is about to register into the Spring {@link ApplicationContext}
|
||
* @param attributes the {@link AnnotationAttributes attributes} of {@link Reference @Reference}
|
||
* @param interfaceClass the {@link Class class} of Service interface
|
||
* @since 2.7.3
|
||
*/
|
||
private void registerReferenceBean(String referencedBeanName, ReferenceBean referenceBean,
|
||
AnnotationAttributes attributes,
|
||
Class<?> interfaceClass) {
|
||
|
||
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
|
||
|
||
// 就是referenceBeanName
|
||
String beanName = getReferenceBeanName(attributes, interfaceClass);
|
||
|
||
// 当前Spring容器中是否存在referencedBeanName
|
||
if (existsServiceBean(referencedBeanName)) { // If @Service bean is local one
|
||
/**
|
||
* Get the @Service's BeanDefinition from {@link BeanFactory}
|
||
* Refer to {@link ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition}
|
||
*/
|
||
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition(referencedBeanName);
|
||
RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) beanDefinition.getPropertyValues().get("ref"); // ServiceBean --- ref
|
||
// The name of bean annotated @Service
|
||
String serviceBeanName = runtimeBeanReference.getBeanName(); // DemoServiceImpl对应的beanName
|
||
// register Alias rather than a new bean name, in order to reduce duplicated beans
|
||
// DemoServiceImpl多了一个别名
|
||
beanFactory.registerAlias(serviceBeanName, beanName);
|
||
} else { // Remote @Service Bean
|
||
if (!beanFactory.containsBean(beanName)) {
|
||
/*
|
||
1.放入Spring容器里的应该是DemoService的实现类的代理对象,但是这里放的却是referenceBean类型对象
|
||
2.referenceBean的父类有个get()可以直接获取到代理对象,那这里为啥不放呢?其实是为了支持@Autowire注解
|
||
3.首先ReferenceBean实现了Spring的FactoryBean接口,FactoryBean获取对象时是这样的调用顺序
|
||
FactoryBean.getObject() ==> getObject().get() ==>最终调子类ReferenceBean#get()
|
||
刚好给@Autowire注解注入了代理对象
|
||
*/
|
||
beanFactory.registerSingleton(beanName, referenceBean);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get the bean name of {@link ReferenceBean} if {@link Reference#id() id attribute} is present,
|
||
* or {@link #generateReferenceBeanName(AnnotationAttributes, Class) generate}.
|
||
*
|
||
* @param attributes the {@link AnnotationAttributes attributes} of {@link Reference @Reference}
|
||
* @param interfaceClass the {@link Class class} of Service interface
|
||
* @return non-null
|
||
* @since 2.7.3
|
||
*/
|
||
private String getReferenceBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
|
||
// id attribute appears since 2.7.3
|
||
String beanName = getAttribute(attributes, "id");
|
||
|
||
// beanName为null时会进入if判断
|
||
if (!hasText(beanName)) {
|
||
beanName = generateReferenceBeanName(attributes, interfaceClass);
|
||
}
|
||
return beanName;
|
||
}
|
||
|
||
/**
|
||
* Build the bean name of {@link ReferenceBean}
|
||
*
|
||
* @param attributes the {@link AnnotationAttributes attributes} of {@link Reference @Reference}
|
||
* @param interfaceClass the {@link Class class} of Service interface
|
||
* @return
|
||
* @since 2.7.3
|
||
*/
|
||
private String generateReferenceBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
|
||
StringBuilder beanNameBuilder = new StringBuilder("@Reference");
|
||
|
||
if (!attributes.isEmpty()) {
|
||
beanNameBuilder.append('(');
|
||
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
|
||
beanNameBuilder.append(entry.getKey())
|
||
.append('=')
|
||
.append(entry.getValue())
|
||
.append(',');
|
||
}
|
||
// replace the latest "," to be ")"
|
||
beanNameBuilder.setCharAt(beanNameBuilder.lastIndexOf(","), ')');
|
||
}
|
||
|
||
beanNameBuilder.append(" ").append(interfaceClass.getName());
|
||
|
||
return beanNameBuilder.toString();
|
||
}
|
||
|
||
private boolean existsServiceBean(String referencedBeanName) {
|
||
return applicationContext.containsBean(referencedBeanName);
|
||
}
|
||
|
||
/**
|
||
* Get or Create a proxy of {@link ReferenceBean} for the specified the type of Dubbo service interface
|
||
*
|
||
* @param referencedBeanName The name of bean that annotated Dubbo's {@link Service @Service} in the Spring {@link ApplicationContext}
|
||
* @param referenceBeanName the bean name of {@link ReferenceBean}
|
||
* @param referenceBean the instance of {@link ReferenceBean}
|
||
* @param serviceInterfaceType the type of Dubbo service interface
|
||
* @return non-null
|
||
* @since 2.7.4
|
||
*/
|
||
private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, ReferenceBean referenceBean, Class<?> serviceInterfaceType) {
|
||
/*
|
||
1.引入的服务在Spirng容器里有,说明是本项目的bean,按理来说应该直接把DemoService的实现类赋给@Reference注解标注的属性
|
||
2.但实际上不是,@Reference实际上最后赋值的是一个代理对象,因为除开需要执行DemoService的实现类里的方法,@Reference
|
||
注解标注的属性还需要实现其它很多逻辑,实现这些增强逻辑之后最终才执行的DemoService的实现类里的方法。如果直接赋值
|
||
DemoServiceImpl,那么Dubbo里面的很多逻辑就走不到了
|
||
*/
|
||
if (existsServiceBean(referencedBeanName)) { // If the local @Service Bean exists, build a proxy of ReferenceBean
|
||
//wrapInvocationHandler最后也会调用referenceBean.get(),其实和下面的else一样
|
||
return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType},
|
||
wrapInvocationHandler(referenceBeanName, referenceBean));
|
||
} else { // ReferenceBean should be initialized and get immediately
|
||
// 重点,最终从这里赋值给@Reference注解标注的属性
|
||
return referenceBean.get();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Wrap an instance of {@link InvocationHandler} that is used to get the proxy of {@link ReferenceBean} after
|
||
* the specified local referenced bean that annotated {@link @Service} exported.
|
||
*
|
||
* @param referenceBeanName the bean name of {@link ReferenceBean}
|
||
* @param referenceBean the instance of {@link ReferenceBean}
|
||
* @return non-null
|
||
* @since 2.7.4
|
||
*/
|
||
private InvocationHandler wrapInvocationHandler(String referenceBeanName, ReferenceBean referenceBean) {
|
||
return localReferenceBeanInvocationHandlerCache.computeIfAbsent(referenceBeanName, name ->
|
||
new ReferenceBeanInvocationHandler(referenceBean));
|
||
}
|
||
|
||
private static class ReferenceBeanInvocationHandler implements InvocationHandler {
|
||
|
||
private final ReferenceBean referenceBean;
|
||
|
||
private Object bean;
|
||
|
||
private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) {
|
||
this.referenceBean = referenceBean;
|
||
}
|
||
|
||
@Override
|
||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||
Object result;
|
||
try {
|
||
if (bean == null) { // If the bean is not initialized, invoke init()
|
||
// issue: https://github.com/apache/dubbo/issues/3429
|
||
init();
|
||
}
|
||
result = method.invoke(bean, args);
|
||
} catch (InvocationTargetException e) {
|
||
// re-throws the actual Exception.
|
||
throw e.getTargetException();
|
||
}
|
||
return result;
|
||
}
|
||
|
||
private void init() {
|
||
this.bean = referenceBean.get();
|
||
}
|
||
}
|
||
|
||
@Override
|
||
protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes, Object bean, String beanName,
|
||
Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) {
|
||
return buildReferencedBeanName(attributes, injectedType) +
|
||
"#source=" + (injectedElement.getMember()) +
|
||
"#attributes=" + AnnotationUtils.resolvePlaceholders(attributes, getEnvironment());
|
||
}
|
||
|
||
/**
|
||
* @param attributes the attributes of {@link Reference @Reference}
|
||
* @param serviceInterfaceType the type of Dubbo's service interface
|
||
* @return The name of bean that annotated Dubbo's {@link Service @Service} in local Spring {@link ApplicationContext}
|
||
*/
|
||
private String buildReferencedBeanName(AnnotationAttributes attributes, Class<?> serviceInterfaceType) {
|
||
ServiceBeanNameBuilder serviceBeanNameBuilder = create(attributes, serviceInterfaceType, getEnvironment());
|
||
return serviceBeanNameBuilder.build();
|
||
}
|
||
|
||
private ReferenceBean buildReferenceBeanIfAbsent(String referenceBeanName, AnnotationAttributes attributes,
|
||
Class<?> referencedType)
|
||
throws Exception {
|
||
|
||
/*
|
||
1.key就是@Reference注解最终生成的字符串,value却不是简单的代理对象
|
||
2.一个ServiceBean表示一个Dubbo服务,ReferenceBean表示引用的哪个dubbo服务
|
||
3.所以ReferenceBean不是简单的代理对象,他保存了诸如超时时间,轮询参数等等这些东西
|
||
【和ServcieBean很类似,ServcieBean也保存了这些东西】
|
||
4.ReferenceBean的父类ReferenceConfig#get()最终返回代理对象
|
||
5.ServiceBean和ReferenceBean思想基本上是一样的
|
||
6.ReferenceBean最终会放入缓存,赋值给@Reference注解所标注的属性的依然是代理对象
|
||
*/
|
||
ReferenceBean<?> referenceBean = referenceBeanCache.get(referenceBeanName);
|
||
|
||
if (referenceBean == null) {
|
||
|
||
// 生成了一个ReferenceBean对象,attributes是@Reference注解的参数值
|
||
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
|
||
.create(attributes, applicationContext)
|
||
.interfaceClass(referencedType);
|
||
referenceBean = beanBuilder.build();
|
||
|
||
referenceBeanCache.put(referenceBeanName, referenceBean);
|
||
} else if (!referencedType.isAssignableFrom(referenceBean.getInterfaceClass())) {
|
||
throw new IllegalArgumentException("reference bean name " + referenceBeanName + " has been duplicated, but interfaceClass " +
|
||
referenceBean.getInterfaceClass().getName() + " cannot be assigned to " + referencedType.getName());
|
||
}
|
||
return referenceBean;
|
||
}
|
||
|
||
private void cacheInjectedReferenceBean(ReferenceBean referenceBean,
|
||
InjectionMetadata.InjectedElement injectedElement) {
|
||
if (injectedElement.getMember() instanceof Field) {
|
||
injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
|
||
} else if (injectedElement.getMember() instanceof Method) {
|
||
injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||
this.applicationContext = applicationContext;
|
||
}
|
||
|
||
@Override
|
||
public void onApplicationEvent(ApplicationEvent event) {
|
||
if (event instanceof ServiceBeanExportedEvent) {
|
||
onServiceBeanExportEvent((ServiceBeanExportedEvent) event);
|
||
} else if (event instanceof ContextRefreshedEvent) {
|
||
onContextRefreshedEvent((ContextRefreshedEvent) event);
|
||
}
|
||
}
|
||
|
||
private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) {
|
||
ServiceBean serviceBean = event.getServiceBean();
|
||
initReferenceBeanInvocationHandler(serviceBean);
|
||
}
|
||
|
||
private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) {
|
||
String serviceBeanName = serviceBean.getBeanName();
|
||
// Remove ServiceBean when it's exported
|
||
ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName);
|
||
// Initialize
|
||
if (handler != null) {
|
||
handler.init();
|
||
}
|
||
}
|
||
|
||
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
|
||
|
||
}
|
||
|
||
|
||
@Override
|
||
public void destroy() throws Exception {
|
||
super.destroy();
|
||
this.referenceBeanCache.clear();
|
||
this.localReferenceBeanInvocationHandlerCache.clear();
|
||
this.injectedFieldReferenceBeanCache.clear();
|
||
this.injectedMethodReferenceBeanCache.clear();
|
||
}
|
||
}
|
||
|
||
``` |