--- 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整合原理与源码分析 #### 处理@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); } } } ``` #### 流程 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 configClass = attributes.getClass("type"); boolean multiple = attributes.getBoolean("multiple"); registerDubboConfigBeans(prefix, configClass, multiple, registry); } private void registerDubboConfigBeans(String prefix, Class configClass, boolean multiple, BeanDefinitionRegistry registry) { // 从properties文件中根据前缀拿对应的配置项,比如根据dubbo.application前缀, // 就可以拿到: // dubbo.application.name=dubbo-demo-provider-application // dubbo.application.logger=log4j Map 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 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 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 resolveMultipleBeanNames(Map properties) { Set beanNames = new LinkedHashSet(); // 比如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 properties, Class 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 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 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 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 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 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 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注解 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()**,这个方法就是**服务导出的入口方法**。 ##### 代码注释 > 部分代码注释 ```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 packagesToScan; private Environment environment; private ResourceLoader resourceLoader; private ClassLoader classLoader; public ServiceAnnotationBeanPostProcessor(String... packagesToScan) { this(Arrays.asList(packagesToScan)); } public ServiceAnnotationBeanPostProcessor(Collection packagesToScan) { this(new LinkedHashSet<>(packagesToScan)); } public ServiceAnnotationBeanPostProcessor(Set packagesToScan) { this.packagesToScan = packagesToScan; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { Set 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 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 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 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 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 protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames); if (!protocolRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); } return builder.getBeanDefinition(); } } ``` #### ReferenceAnnotationBeanPostProcessor > 处理@Reference注解 ##### 总结 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... 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 fieldElements = findFieldAnnotationMetadata(beanClass); // 哪些方法上有@Reference注解 Collection 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 fieldElements; private final Collection methodElements; public AnnotatedInjectionMetadata(Class targetClass, Collection fieldElements, Collection methodElements) { super(targetClass, combine(fieldElements, methodElements)); this.fieldElements = fieldElements; this.methodElements = methodElements; } public Collection getFieldElements() { return fieldElements; } public Collection 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> referenceBeanCache = new ConcurrentHashMap<>(CACHE_SIZE); private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache = new ConcurrentHashMap<>(CACHE_SIZE); private final ConcurrentMap> injectedFieldReferenceBeanCache = new ConcurrentHashMap<>(CACHE_SIZE); private final ConcurrentMap> 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> getReferenceBeans() { return referenceBeanCache.values(); } /** * Get {@link ReferenceBean} {@link Map} in injected field. * * @return non-null {@link Map} * @since 2.5.11 */ public Map> getInjectedFieldReferenceBeanMap() { return Collections.unmodifiableMap(injectedFieldReferenceBeanCache); } /** * Get {@link ReferenceBean} {@link Map} in injected method. * * @return non-null {@link Map} * @since 2.5.11 */ public Map> 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 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(); } } ```