dubbo之注解配置

wang0907 2022-01-08 03:26:41 阅读数:82

dubbo 注解 配置

1:寫在前面

這篇文章 中我們分析了通過xml配置方式配置解析的過程,本文一起來看下基於注解配置方式,即Java config方式配置的解析過程。另外關於dubbo注解配置使用可以參考如下的文章列錶:

dubbo之入門

dubbo之外部化配置

如下是服務提供者端一個可能的配置:

@Configuration
@EnableDubbo(scanBasePackages = "dongshi.daddy.service.annotation")
public class DubboConfiguration {

@Bean // #1 服務提供者信息配置
public ProviderConfig providerConfig() {

ProviderConfig providerConfig = new ProviderConfig();
providerConfig.setTimeout(1000);
return providerConfig;
}
@Bean // #2 分布式應用信息配置,相當於xml配置:<dubbo:application name="dongshidaddy-provider" owner="dongshidaddy">
public ApplicationConfig applicationConfig() {

ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-annotation-provider");
return applicationConfig;
}
@Bean // #3 注册中心信息配置,相當於xml配置:<dubbo:registry address="zookeeper://192.168.10.119:2181" />
public RegistryConfig registryConfig() {

RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("192.168.10.119");
registryConfig.setPort(2181);
return registryConfig;
}
@Bean // #4 使用協議配置,這裏使用 dubbo,相當於xml配置:<dubbo:protocol name="dubbo" port="20823"/>
public ProtocolConfig protocolConfig() {

ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(20885);
return protocolConfig;
}
}

啟動類:

public class ProviderAnnotationMain {

public static void main(String[] args) {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DubboConfiguration.class);
context.start();
new Thread(() -> {

while (true) {

try {

Thread.sleep(900000);
} catch (InterruptedException e) {

e.printStackTrace();
}
}
}).start();
}
}

服務消費者端配置:

@Configuration
@EnableDubbo(scanBasePackages = "dongshi.daddy.service.annotation")
@ComponentScan(value = {
"dongshi.daddy.service.annotation"})
public class ConsumerConfiguration {

@Bean // 應用配置
public ApplicationConfig applicationConfig() {

ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-annotation-consumer");
Map<String, String> stringStringMap = new HashMap<String, String>();
stringStringMap.put("qos.enable","true");
stringStringMap.put("qos.accept.foreign.ip","false");
stringStringMap.put("qos.port","33333");
applicationConfig.setParameters(stringStringMap);
return applicationConfig;
}
@Bean // 服務消費者配置
public ConsumerConfig consumerConfig() {

ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setTimeout(3000);
return consumerConfig;
}
@Bean // 配置注册中心
public RegistryConfig registryConfig() {

RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("192.168.10.119");
registryConfig.setPort(2181);
return registryConfig;
}
}

啟動類:

public class ConsumerAnnotationMain {

public static void main(String[] args) {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start(); // 啟動
ConsumerAnnotationService consumerAnnotationService = context.getBean(ConsumerAnnotationService.class);
String hello = consumerAnnotationService.doSayHello("annotation"); // 調用方法
System.out.println("result: " + hello); // 輸出結果
}
}

2. @EnableDubbo

類全限定名稱是com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo,源碼如下:

@Target({
ElementType.TYPE}) // 用在類上
@Retention(RetentionPolicy.RUNTIME) // 保留到運行時
@Inherited // 可以被繼承
@Documented
@EnableDubboConfig
@DubboComponentScan // 啟用dubbo組件的掃描,即掃描@Service注解的服務提供者類,@Reference注解的服務消費者類
public @interface EnableDubbo {

// 掃描使用了@Service,@Reference注解的類的基礎包,是相當於使用DubboComponentScan.class注解的basePackages
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {
};
// 同scanBasePackages直接以字符串的方式來指定要掃描的包的集合,該值指定一組class後,會以class所在的包路徑來掃描@Service和@Reference注解的類
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {
};
// 暫時不知道幹啥用的
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
}

可以看到該注解組合了注解@EnableDubboConfig和注解DubboComponentScan,接下來我們先來看下@EnableDubboConfig注解。

3. @EnableDubboConfig

源碼如下:

@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {

// 是否允許dubbo多配置bean綁定,2.5.8版本引入默認為false,2.5.9版本開始修改為默認true
boolean multiple() default true;
}

可以看到源碼中通過@Import(DubboConfigConfigurationRegistrar.class)引入了bean定義,因此,接下來我們看下DubboConfigConfigurationRegistrar到底做了什麼操作。

3.1:DubboConfigConfigurationRegistrar

源碼如下:

public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

// 獲取@EnableDubboConfig配置的屬性信息
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
// 獲取multiple屬性的值
boolean multiple = attributes.getBoolean("multiple");
// 2021-12-27 13:30:24
registerBeans(registry, DubboConfigConfiguration.Single.class);
// 2021-12-27 13:30:45
if (multiple) {
 // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
}
}

2021-12-27 13:30:24處是默認注册一個DubboConfigConfiguration.Single的內部類的bean,2021-12-27 13:30:45處是如果是開啟了多dubbo配置bean綁定則注册DubboConfigConfiguration.Multiple內部類,可以看到都是DubboConfigConfiguration的內部類,源碼如下:

public class DubboConfigConfiguration {

// 單dubbo配置bean綁定
@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)
})
public static class Single {

}
// 多dubbo配置bean綁定,注意都設置了"multiple = true"
@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)
})
public static class Multiple {

}
}

可以看到都是用了@EnableDubboConfigBindings@EnableDubboConfigBinding注解,這兩個注解是用來設置指定外部配置文件屬性前綴綁定到AbstractConfig的子類的,下面來一起看下都完成了哪些工作。@EnableDubboConfigBindings參考3.2:@EnableDubboConfigBindings,@EnableDubboConfigBinding參考3.3:@EnableDubboConfigBinding

3.2:@EnableDubboConfigBindings

源碼如下:

@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {

EnableDubboConfigBinding[] value();
}

可以看到使用了@Import(DubboConfigBindingsRegistrar.class)來引入bean定義。

3.2.1:DubboConfigBindingsRegistrar

源碼如下:

public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

// 環境
private ConfigurableEnvironment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

// 獲得類上標注的@EnableDubboConfigBindings屬性信息
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
// 獲取value值,即使用@EnableDubboConfigBinding注解配置的屬性前綴和AbstractConfig子類的對應關系
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
// 創建DubboConfigBindingRegistrar並使用其完成dubbo注册
DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
registrar.setEnvironment(environment);
for (AnnotationAttributes element : annotationAttributes) {

// 2021-12-28 13:31:38
registrar.registerBeanDefinitions(element, registry);
}
}
@Override
public void setEnvironment(Environment environment) {

Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
this.environment = (ConfigurableEnvironment) environment;
}
}

2021-12-28 13:31:38處是注册單個映射關系的bean定義,具體參考3.3.1:DubboConfigBindingRegistrar

3.3:@EnableDubboConfigBinding

源碼如下:

// 啟用外部化配置,從@PropertySource注解指定的配置文件中讀取相關配置映射綁定到AbstractConfig對應的子類中,前綴比如"dubbo.application.",`dubbo.application`
@Target({
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingRegistrar.class)
public @interface EnableDubboConfigBinding {

// 能够綁定到AbstractConfig子類的屬性前綴
String prefix();
// 要綁定的AbstractConfig子類
Class<? extends AbstractConfig> type();
// 是否支持綁定到多個spring bean
boolean multiple() default false;
}

通過@Import(DubboConfigBindingRegistrar.class)引入相關的spring bean,具體參考3.3.1:DubboConfigBindingRegistrar

3.3.1:DubboConfigBindingRegistrar

源碼如下:

public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

private final Log log = LogFactory.getLog(getClass());
private ConfigurableEnvironment environment;
protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {

// 獲取在@EnableDubboConfigBinding注解中配置的prefix值,如dubbo.application
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
// 獲取在@EnableDubboConfigBinding注解中type的值,即設置的要綁定的AbtractConfig子類
Class<? extends AbstractConfig> configClass = attributes.getClass("type");
// 獲取multiple屬性的值,即是否支持dubbo多配置bean綁定
boolean multiple = attributes.getBoolean("multiple");
registerDubboConfigBeans(prefix, configClass, multiple, registry);
}
private void registerDubboConfigBeans(String prefix,
Class<? extends AbstractConfig> configClass,
boolean multiple,
BeanDefinitionRegistry registry) {

// 獲取配置文件中以prefix開頭的配置信息,如獲取dubbo.application開頭的,如下配置:
/* dubbo.application.name=dongshidaddy-provider dubbo.application.owner=dongshidaddy */
// 則這裏獲取的結果就是:
/* "owner" -> "dongshidaddy" "name" -> "dongshidaddy-provider" */
Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);
// 沒有對應的外部配置屬性,不報錯,只是給出日志,就return
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;
}
// 2021-12-29 14:15:46
// 獲取綁定的AbstractConfig的bean名稱集合
Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
for (String beanName : beanNames) {

// 將bean定義注册到BeanDefinitionRegistry registry中
registerDubboConfigBean(beanName, configClass, registry);
// 2021-12-29 16:24:02
// 注册DubboConfigBindingBeanPostProcessor後置bean處理器,關於BeanPostProcessort可以參考:
// https://blog.csdn.net/wang0907/article/details/114798943
// https://blog.csdn.net/wang0907/article/details/115440135
registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
}
}
}

2021-12-29 14:15:46處是注册bean名稱,multiple=false時resolveSingleBeanName,源碼如下:

class FakeCls {

private String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass,
BeanDefinitionRegistry registry) {

// 獲取id屬性,如dubbo.application.id=myApplicationConfigBean,則使用myApplicationConfigBean
String beanName = (String) properties.get("id");
// 沒有配置id屬性,則使用“類全限定名稱+#序號”方式生成結果,如com.alibaba.dubbo.config.ApplicationConfig
// 則結果可能是com.alibaba.dubbo.config.ApplicationConfig#0
if (!StringUtils.hasText(beanName)) {

BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
}
// 返回bean名稱
return beanName;
}
}

multiple=true時resolveMultipleBeanNames源碼如下:

class FakeCls {

private Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {

// 以dubbo.application為例多配置bean格式為dubbo.applications.${bean名稱}.${屬性名稱} = 屬性值,比如配置如下:
/* dubbo.applications.applicationBean.name = dubbo-demo-application dubbo.applications.applicationBean2.name = dubbo-demo-application2 dubbo.applications.applicationBean3.name = dubbo-demo-application3 */
// 則properties結果就是:
/* "applicationBean.name" -> "dubbo-demo-application" "applicationBean2.name" -> "dubbo-demo-application2" "applicationBean3.name" -> "dubbo-demo-application3" */
// 其中的applicationBean,applicationBean2,applicationBean3就是就是我們需要的bean名稱
Set<String> beanNames = new LinkedHashSet<String>();
for (String propertyName : properties.keySet()) {

int index = propertyName.indexOf(".");
if (index > 0) {

String beanName = propertyName.substring(0, index);
beanNames.add(beanName);
}
}
return beanNames;
}
}

2021-12-29 16:24:02處是添加後置bean處理器,具體參考3.4:DubboConfigBindingBeanPostProcessor,主要是完成的工作是填充配置bean的相關屬性,從前面的分析我們看到只是創建了配置bean的bean定義並沒有填充屬性,解析來再來看下這個屬性填充的過程。

3.4:DubboConfigBindingBeanPostProcessor

這是一個後置bean處理器的實現類,關於後置bean處理器可以參考這篇文章

3.4.1:構造方法
class FakeCls {

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");
// 外部化配置屬性前綴,如dubbo.application
this.prefix = prefix;
// 外部化配置對應的AbstractConfig子類的bean名稱
this.beanName = beanName;
}
}
3.4.2:afterPropertiesSet

因為實現了InitializingBean接口所以會在DubboConfigBindingBeanPostProcessor bean創建完畢並設置屬性完畢後調用afterPropertiesSet方法,主要是設置config bean的後置處理時需要的相關對象,如用來設置config bean屬性的DataBinder等,源碼如下:

class FakeCls {

public void afterPropertiesSet() throws Exception {

// 2021-12-30 19:29:47
initDubboConfigBinder();
// 2021-12-30 19:29:53
initConfigBeanCustomizers();
}
}

2021-12-30 19:29:47處是設置DataBinder (spring提供的用於進行屬性綁定的API)`,具體源碼如下:

class FakeCls {

private void initDubboConfigBinder() {

if (dubboConfigBinder == null) {

try {

dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);
} catch (BeansException ignored) {

if (log.isDebugEnabled()) {

log.debug("DubboConfigBinder Bean can't be found in ApplicationContext.");
}
/* protected DubboConfigBinder createDubboConfigBinder(Environment environment) { DefaultDubboConfigBinder defaultDubboConfigBinder = new DefaultDubboConfigBinder(); defaultDubboConfigBinder.setEnvironment(environment); return defaultDubboConfigBinder; } */
dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());
}
}
// 忽略未知字段
dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
// 忽略無效字段
dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);
}
}

DubboConfigBinder是直接使用的DataBinder來綁定外部配置文件屬性信息到AbstractConfig子類的屬性中,源碼如下:

public class DefaultDubboConfigBinder extends AbstractDubboConfigBinder {

@Override
public <C extends AbstractConfig> void bind(String prefix, C dubboConfig) {

DataBinder dataBinder = new DataBinder(dubboConfig);
// 設置忽略無效屬性
dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());
// 設置忽略未知屬性
dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());
// 從@PropertySource注解指定的配置文件中獲取指定前綴的屬性
Map<String, Object> properties = getSubProperties(getPropertySources(), prefix);
// 轉換Map為MutablePropertyValues
MutablePropertyValues propertyValues = new MutablePropertyValues(properties);
// 調用DataBinder的API完成綁定,即設置AbstractConfig子類的屬性的值
dataBinder.bind(propertyValues);
}
}

可以看到上面的代碼就完成的外部屬性設置到AbtractConfig子類的bean中的工作,那麼是什麼時候調用的呢,具體參考3.4.4:postProcessBeforeInitialization
2021-12-30 19:29:53處是獲取並設置針對config spring bean進行定義的對象,是一個擴展的口,如下:

class FakeCls {

private void initConfigBeanCustomizers() {

// 從容器中獲取類型為DubboConfigBeanCustomizer的所有spring bean
Collection<DubboConfigBeanCustomizer> configBeanCustomizers =
beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values();
// 賦值到全局屬性中,供後續使用
this.configBeanCustomizers = new ArrayList<DubboConfigBeanCustomizer>(configBeanCustomizers);
// 排序
AnnotationAwareOrderComparator.sort(this.configBeanCustomizers);
}
}
3.4.4:postProcessBeforeInitialization

通過後置bena處理器的postProcessBeforeInitialization方法,即初始化spring bean之前設置對象屬性,源碼如下:

class FakeCls {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) {

AbstractConfig dubboConfig = (AbstractConfig) bean;
// 2021-12-31 13:45:09
bind(prefix, dubboConfig);
customize(beanName, dubboConfig);
}
return bean;
}
}

2021-12-31 13:45:09處是綁定屬性,源碼如下:

class FakeCls {

private void bind(String prefix, AbstractConfig dubboConfig) {

// 調用的就是DefaultDubboConfigBinder#bind方法,在"3.4.2:afterPropertiesSet"已經進行了講解
dubboConfigBinder.bind(prefix, dubboConfig);
if (log.isInfoEnabled()) {

log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " +
"configuration properties : " + prefix);
}
}
}

到這裏config bean就創建完畢並且屬性也填充完畢了。dubbo配置相關的spring bean是如何創建的已經分析完了,接下來在看下第二部分重要的spring bean,即使用了@Service注解和@Reference注解的spring bean,dubbo定義了@DubboComponentScan注解來定義掃描哪些目錄加載使用了相關注解的類為spring bean,接著就來一起看下這部分的內容。

4:@DubboComponentScan

該注解用來掃描指定包路徑下使用了@Service@Reference注解的類,從而創建對應的spring bean對象,源碼如下:

// 從classpath下掃描使用了@Service,@Reference注解的類自動注册為spring beans
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {

// 設置要掃描的基礎包路徑
String[] value() default {
};
// 設置要要掃描的包路徑
String[] basePackages() default {
};
// 通過設置Class來指定要掃描的基礎包路徑,即Class所在的包
Class<?>[] basePackageClasses() default {
};
}

@Import(DubboComponentScanRegistrar.class)注解可以看出是通過DubboComponentScanRegistrar類來完成掃描和注册spring bean的。

4.1:DubboComponentScanRegistrar

該類處理@DubboComponentScan注解,注册@Service注解對應的ServiceAnnotationBeanPostProcessor和@Reference注解對應的ReferenceAnnotationBeanPostProcessor後置bean處理器到spring 容器中,以便對@Service和@Reference對應的spring bean進行後置處理。源碼如下:

class FakeCls {

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

// 2021-12-31 15:02:34
// 獲取要掃描的包路徑集合,配置@DubboComponentScan(basePackages = { "dongshi.daddy.service.multipleexternalconfig" }),這裏的結果就是:
// 0 = dongshi.daddy.service.multipleexternalconfig
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 2021-12-31 14:42:55
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 2021-12-31 14:43:08
registerReferenceAnnotationBeanPostProcessor(registry);
}
}

2021-12-31 14:42:55處是設置@Service注解對應的ServiceAnnotationBeanPostProcessor,具體參考4.1.1:registerServiceAnnotationBeanPostProcessor2021-12-31 14:43:08,ServiceAnnotationBeanPostProcessor具體參考4.2:ServiceAnnotationBeanPostProcessor。處是設置@Reference注解對應的ReferenceAnnotationBeanPostProcessor,ReferenceAnnotationBeanPostProcessor具體參考4.3:ReferenceAnnotationBeanPostProcessor2021-12-31 15:02:34處源碼如下:

class FakeCls {

private Set<String> getPackagesToScan(AnnotationMetadata metadata) {

// 獲取@DubboComponentScan配置的屬性值
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
// 獲取basePackages,basePackageClasses,value數組,三者都是用來配置要掃描的包路徑的
String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
String[] value = attributes.getStringArray("value");
// 轉通過value配置的包路徑為set集合
Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
// 添加通過basePackage屬性配置的包路徑到要掃描的包路徑集合中,此時value和basePackages會做一個並集
packagesToScan.addAll(Arrays.asList(basePackages));
// 添加通過basePackageClasses配置的包路徑掃到要掃描的包路徑集合中,此時value,basePackages,basePakcageClasess三者做了並集
for (Class<?> basePackageClass : basePackageClasses) {

packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
}
// 如果是沒有要掃描的包路徑,則使用當前Java config類所在包路徑作為要掃描的基礎包路徑
// 如public class MyMultipleExternalConfigConfiguration {},所在包為package dongshi.daddy.service.multipleexternalconfig;
// 則這裏的結果就是dongshi.daddy.service.multipleexternalconfig
if (packagesToScan.isEmpty()) {

return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
}
return packagesToScan;
}
}

4.1.1:registerServiceAnnotationBeanPostProcessor

源碼如下:

class FakeCls {

private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

// 構造器設計模式,創建用於構造BeanDefinition的構造器,源碼如下:
/* public static BeanDefinitionBuilder rootBeanDefinition(Class<?> beanClass, String factoryMethodName) { BeanDefinitionBuilder builder = new BeanDefinitionBuilder(); builder.beanDefinition = new RootBeanDefinition(); builder.beanDefinition.setBeanClass(beanClass); builder.beanDefinition.setFactoryMethodName(factoryMethodName); return builder; } */
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
// 添加構造函數參數,這裏添加的是要掃描的包路徑
builder.addConstructorArgValue(packagesToScan);
// 設置角色,這裏設置該bean定義為純粹內部使用,和外部用戶沒有任何關系,正常可以忽略該屬性
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 從構造器中獲取創建的RootBeanDefinition
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 注册bean定義到bean定義注册器中
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
}

4.1.2:registerReferenceAnnotationBeanPostProcessor

源碼如下:

class FakeCls {

private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {

// 獲取bean名稱為public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";的bean,默認為需要的ReferenceAnnotaionBeanPostProcessor的bean,源碼如下:
/* public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry, String beanName, Class<?> beanType) { // 不包含則重新創建並添加到bean定義注册器中 if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition); } } */
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
}
}

4.2:ServiceAnnotationBeanPostProcessor

4.2.1:構造方法

class FakeCls {

public ServiceAnnotationBeanPostProcessor(String... packagesToScan) {

this(Arrays.asList(packagesToScan));
}
public ServiceAnnotationBeanPostProcessor(Collection<String> packagesToScan) {

this(new LinkedHashSet<String>(packagesToScan));
}
public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) {

this.packagesToScan = packagesToScan;
}
}

4.2.2:postProcessBeanDefinitionRegistry

因為實現了接口BeanDefinitionRegistryPostProcessor所以會在將bean定義全部注册到BeanDefinitionRegistry之後調用postProcessBeanDefinitionRegistry方法來對bean定義注册器進行修改,

為什麼要實現BeanDefinitionRegistryPostProcessor接口:因為此時spring所有能够識別的(如使用了@Component,@Bean等spring提供的注解)類都已經生成bean definition並注册到BeanDefinitionRegistry中了,但是dubbo提供的@Service注解和@Reference注解,spring的默認機制是不識別的,所以在這個節點來做,就是最合適的了。

源碼如下:

class FakeCls {

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

// 因為可能存在占比特符,所以有此步驟的占比特符替換,源碼如下:
/* private Set<String> resolvePackagesToScan(Set<String> packagesToScan) { Set<String> resolvedPackagesToScan = new LinkedHashSet<String>(packagesToScan.size()); for (String packageToScan : packagesToScan) { if (StringUtils.hasText(packageToScan)) { String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim()); resolvedPackagesToScan.add(resolvedPackageToScan); } } return resolvedPackagesToScan; } */
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {

// 2021-12-31 16:14:05
registerServiceBeans(resolvedPackagesToScan, registry);
} else {

if (logger.isWarnEnabled()) {

logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
}

2021-12-31 16:14:05處是掃描指定的包路徑集合並將有@Service注解的類生成對應的bean definition,具體參考4.2.2.1:registerServiceBeans

4.2.2.1:registerServiceBeans

源碼如下:

class FakeCls {

private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

// 創建用於從classpath的指定包中掃描類的DubboClassPathBeanDefinitionScanner
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
// 解析獲取的bean名稱生成器,源碼如下:
/* private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) { BeanNameGenerator beanNameGenerator = null; if (registry instanceof SingletonBeanRegistry) { SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry); beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); } if (beanNameGenerator == null) { // ... beanNameGenerator = new AnnotationBeanNameGenerator(); } return beanNameGenerator; } */
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// 只過濾標注了@com.alibaba.dubbo.config.annotation.Service注解的類
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
// 一個包一個包的開始掃描生成bean definition
for (String packageToScan : packagesToScan) {

// 掃描注解了@com.alibaba.dubbo.config.annotation.Service注解的類的類
scanner.scan(packageToScan);
// 2021-12-31 16:52:08
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
// 有beanDefinitionHolder,即再掃描的包路徑下有標注了dubbo的@Service注解的類 
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {

// 循環注册到bean定義注册器中
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {

// 2022-01-01 17:04:21
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 + "]");
}
}
}
}
}

2021-12-31 16:52:08處是封裝當前包路徑解析到的bean definition為BeanDefinitionHolder集合,一個bean definition對應一個BeanDefinitionHolder集合,源碼如下:

class FakeCls {

private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(
ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry,
BeanNameGenerator beanNameGenerator) {

// 獲取掃描到的BeanDefinition集合
Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);
Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<BeanDefinitionHolder>(beanDefinitions.size());
for (BeanDefinition beanDefinition : beanDefinitions) {

// 生成bean名稱
String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
beanDefinitionHolders.add(beanDefinitionHolder);
}
return beanDefinitionHolders;
}
}

2022-01-01 17:04:21處是注册bean定義到bean定義注册器中,具體參考4.2.2.1:registerServiceBean

4.2.2.1:registerServiceBean

源碼如下:

class FakeCls {

private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {

// 從beanDefinitionHolder中獲取使用了com.alibaba.dubbo.config.annotation.Service注解的服務提供者類的Class對象
Class<?> beanClass = resolveClass(beanDefinitionHolder);
// 獲取Service注解對象
Service service = findAnnotation(beanClass, Service.class);
// 獲取服務提供接口類型
// 2022-01-01 17:25:37
Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service);
// 獲取bean名稱
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// 創建服務提供類對應的beandefinition對象
// 2022-01-01 20:28:22
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);
// 重新生成bean名稱,更具有業務含義
// ServiceBean Bean name,如ServiceBean:dubbo:dongshi.daddy.service.annotation.ProviderServiceAnnotation
String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName);
// 校驗重複,不存在則中注册bean定義到bean定義注册器中
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) {

// 注册
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?");
}
}
}
}

2022-01-01 17:25:37處是獲取服務提供者接口類型,源碼如下:

class FakeCls {

private Class<?> resolveServiceInterfaceClass(Class<?> annotatedServiceBeanClass, Service service) {

// 首先獲取在Service注解上設置的Class<?> interfaceClass() default void.class;,一般我們不設置所以是默認值void.class
Class<?> interfaceClass = service.interfaceClass();
// 如果是void.class,即獲取的是默認值
if (void.class.equals(interfaceClass)) {

interfaceClass = null;
// 獲取Service注解上配置的String interfaceName() default "";,默認是空串
String interfaceClassName = service.interfaceName();
// 如果是在Service注解上配置了String interfaceName() default "";
if (StringUtils.hasText(interfaceClassName)) {

// 有該類,則解析為Class對象
if (ClassUtils.isPresent(interfaceClassName, classLoader)) {

interfaceClass = resolveClassName(interfaceClassName, classLoader);
}
}
}
// 如果是執行到這裏說明在Service注解上即沒有設置interfaceClass也沒有設置interfaceName
if (interfaceClass == null) {

// 獲取所有的父接口集合,然後取第一個作為目標接口類型,此處在之前版本因為代碼是Class<?>[] allInterfaces = annotatedServiceBeanClass.getInterfaces();
// 這種方式只會獲取直接實現的接口,而不會遞歸獲取父類實現的接口,因此如果不直接實現接口的話就問題了,關於該問題可以查看
// issue:https://github.com/apache/incubator-dubbo/issues/3251
Class<?>[] allInterfaces = ClassUtils.getAllInterfacesForClass(annotatedServiceBeanClass);
if (allInterfaces.length > 0) {

// 取第一個,作為結果
interfaceClass = allInterfaces[0];
}
}
// 斷言獲取到了class對象
Assert.notNull(interfaceClass,
"@Service interfaceClass() or interfaceName() or interface class must be present!");
// 斷言獲取到的class對象是接口類型
Assert.isTrue(interfaceClass.isInterface(),
"The typfe that was annotated @Service is not an interace!");
return interfaceClass;
}
}

2022-01-01 20:28:22處是構造bean定義,具體參考4.2.2.2:buildServiceBeanDefinition

4.2.2.2:buildServiceBeanDefinition

源碼如下:

class FakeCls {

private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass,
String annotatedServiceBeanName) {

// ServiceBean是服務提供者service對應的配置類ServiceConfig的子類,用於進一步封裝信息,這裏返回的是其對應的BeanDefinition的構造器類
// 即使用的是構造器設計模式,使用構造器設計模式的原因是方便靈活設置屬性信息,擺脫構造函數的束縛
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
// 獲取內部封裝的ServiceBean對應的BeanDefinition
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 獲取內部的MutablePropertyValues,方便修改屬性
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
"interface", "interfaceName");
// 使用AnnotationPropertyValuesAdapter,獲取dubbo @Service注解中的屬性,並最終通過addPropertyValues添加到MutablePropertyValues propertyValues
// ,最終添加到ServiceBean對應的beandefinition中,如設置@Service(timeout = 5000, version = "2.3.4"),則會將timeout和version添加
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames));
// 將ServiceBean內部實際的服務提供者類的bean名稱設置ref屬性,個人理解是方便後續查找使用
// 也可以這樣理解,是設置了ServiceBean實際引用的服務提供者類的spring bean是哪個
addPropertyReference(builder, "ref", annotatedServiceBeanName);
// 設置服務提供者類的全限定接口名稱
builder.addPropertyValue("interface", interfaceClass.getName());
// 設置使用的provider的bean,如果是xml的話對應的標簽就是<dubbo:provider>
String providerConfigBeanName = service.provider();
if (StringUtils.hasText(providerConfigBeanName)) {

addPropertyReference(builder, "provider", providerConfigBeanName);
}
// 獲取和設置使用的monitor,對應的xml標簽是<dubbo:monitor>
String monitorConfigBeanName = service.monitor();
if (StringUtils.hasText(monitorConfigBeanName)) {

addPropertyReference(builder, "monitor", monitorConfigBeanName);
}
// 獲取和設置使用的application,對應的xml標簽是<dubbo:application>
String applicationConfigBeanName = service.application();
if (StringUtils.hasText(applicationConfigBeanName)) {

addPropertyReference(builder, "application", applicationConfigBeanName);
}
// 獲取和設置使用的module,對應的xml標簽是<dubbo:module>
String moduleConfigBeanName = service.module();
if (StringUtils.hasText(moduleConfigBeanName)) {

addPropertyReference(builder, "module", moduleConfigBeanName);
}
// 獲取和設置使用的registries,對應的xml標簽是<dubbo:registry>
String[] registryConfigBeanNames = service.registry();
// 可能有多個,所以是List
List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
if (!registryRuntimeBeanReferences.isEmpty()) {

builder.addPropertyValue("registries", registryRuntimeBeanReferences);
}
// 獲取和設置使用的protocols,對應的xml標簽是<dubbo:protocol> 
String[] protocolConfigBeanNames = service.protocol();
// 可能有多個,所以是List
List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
if (!protocolRuntimeBeanReferences.isEmpty()) {

builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
}
// 設置方法配置,如下可能配置:
/* @Service(methods = { @Method(name = "SayHelloAnnotation", timeout = 2000) }) */
Method[] methods = service.methods();
List<MethodConfig> methodConfigs = MethodConfig.constructMethodConfig(methods);
if(!methodConfigs.isEmpty()){

builder.addPropertyValue("methods", methodConfigs);
}
// 獲取bean定義並返回
return builder.getBeanDefinition();
}
}

4.3:ReferenceAnnotationBeanPostProcessor

該後置bean處理器用於處理標注了dubbo @Reference注解的屬性,實現其屬性的注入,如下可能的代碼:

@Component("annotatedConsumer")
public class ConsumerAnnotationService {

@Reference
private ProviderServiceAnnotation providerServiceAnnotation;
public String doSayHello(String name) {

return providerServiceAnnotation.SayHelloAnnotation(name);
}
}

所要作的事情就是為private ProviderServiceAnnotation providerServiceAnnotation屬性注入屬性值。因為是屬性注入,所以ReferenceAnnotationBeanPostProcessor是通過加入spring 提供的inject相關的方法完整自定義的屬性注入的,最終會執行到方法doGetInjectedBean,我們就從這個方法開始吧!

4.3.1:doGetInjectedBean

源碼如下:

class FakeCls {

@Override
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {

// 2022-01-02 19:17:27
String referencedBeanName = buildReferencedBeanName(reference, injectedType);
// 2022-01-02 20:42:39
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
// 添加到緩存,根據是基於屬性注入還是方法注入,加入不同的緩存中,源碼如下:
/* private void cacheInjectedReferenceBean(ReferenceBean referenceBean, InjectionMetadata.InjectedElement injectedElement) { if (injectedElement.getMember() instanceof Field) { // private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanCache = new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE); injectedFieldReferenceBeanCache.put(injectedElement, referenceBean); } else if (injectedElement.getMember() instanceof Method) { // private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanCache = new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE); injectedMethodReferenceBeanCache.put(injectedElement, referenceBean); } } */
cacheInjectedReferenceBean(referenceBean, injectedElement);
// 2022-01-03 10:35:17
Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);
return proxy;
}
}

2022-01-02 19:17:27處是要生成將要引用對象的bean名稱(其實就是通過netty調用遠端服務提供者的代理對象)reference是@Reference注解本身,injectedType是要注入的類型,一般是接口,因為我們都是通過接口來注入對象的,具體參考4.3.1.1:buildReferencedBeanName2022-01-02 20:42:39創建ReferenceBean對象,和ServiceBean對應,具體參考4.3.1.2:buildReferenceBeanIfAbsent,2022-01-03 10:35:17處是構建代理類,具體參考4.3.1.3:buildProxy

4.3.1.1:buildReferencedBeanName

源碼如下:

class FakeCls {

private String buildReferencedBeanName(Reference reference, Class<?> injectedType) {

// 生成bean名稱構造器對象,內容可能如下:
/* category = "consumers" protocol = "dubbo" interfaceClassName = "dongshi.daddy.service.annotation.ProviderServiceAnnotation" version = "" group = "" environment = null */
AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType);
// 設置環境,用於替換可能存在的占比特符
builder.environment(getEnvironment());
// 替換占比特符並返回結果,build方法如下:
/* // 格式:${category}:${protocol}:${serviceInterface}:${version}:${group} public String build() { // 追加必須的屬性信息,category:{provider|consumer} StringBuilder beanNameBuilder = new StringBuilder(category); // 追加協議,如dubbo,zookeeper append(beanNameBuilder, protocol); append(beanNameBuilder, interfaceClassName); // 替換可選屬性 append(beanNameBuilder, version); append(beanNameBuilder, group); String beanName = beanNameBuilder.toString(); // 替換占比特符 return environment != null ? environment.resolvePlaceholders(beanName) : beanName; } */
// 從build方法的源碼中可以看到其實已經執行過替換占比特符的操作,不知道為何這裏又重複執行替換占比特符操作
return getEnvironment().resolvePlaceholders(builder.build());
}
}
4.3.1.2:buildReferenceBeanIfAbsent

源碼如下:

class FakeCls {

private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference,
Class<?> referencedType, ClassLoader classLoader)
throws Exception {

// 先從緩存中獲取,為什麼要使用緩存,為了複用
ReferenceBean<?> referenceBean = referenceBeanCache.get(referencedBeanName);
// 緩存中沒有
if (referenceBean == null) {

// 使用ReferenceBeanBuilder構造器類來構造ReferenceBean(又是構造器設計模式)
// 2022-01-02 20:51:45
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
.create(reference, classLoader, applicationContext)
.interfaceClass(referencedType);
// 構造
referenceBean = beanBuilder.build();
// 放到緩存中
referenceBeanCache.put(referencedBeanName, referenceBean);
}
// 返回
return referenceBean;
}
}

2022-01-02 20:51:45處是使用ReferenceBeanBuilder類來構造ReferenceBean,關於ReferenceBeanBuilder類參考4.3.2:ReferenceBeanBuilder

4.3.1.3:buildProxy

源碼如下:

class FakeCls {

private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class<?> injectedType) {

// 2022-01-03 19:03:53
// 生成jdk動態代理中的java.lang.reflect.InvocationHandler
InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean);
// 使用java.lang.reflect.Proxy#newProxyInstance方法生成jdk的動態代理類
Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{
injectedType}, handler);
return proxy;
}
}

2022-01-03 19:03:53處就是動態代理的核心邏輯了,提供了java.lang.reflect.InvocationHandler實現類,執行具體的代理執行邏輯,具體參考``。

4.3.2:ReferenceBeanBuilder

4.3.3:buildInvocationHandler

源碼如下:

class FakeCls {

private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) {

// 先從緩存中獲取,private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> localReferenceBeanInvocationHandlerCache = new ConcurrentHashMap<String, ReferenceBeanInvocationHandler>(CACHE_SIZE);
ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName);
// 沒有,new一個ReferenceBeanInvocationHandler,這是InvocationHandler的子類
// private static class ReferenceBeanInvocationHandler implements InvocationHandler {}
if (handler == null) {

// referenceBean參數:封裝了服務接口的ReferenceBean對象
handler = new ReferenceBeanInvocationHandler(referenceBean);
}
if (applicationContext.containsBean(referencedBeanName)) {
 // Is local @Service Bean or not ?
// ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported.
localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
} else {

// Remote Reference Bean should initialize immediately
handler.init();
}
return handler;
}
}
版权声明:本文为[wang0907]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201080326407272.html