Dubbo源码分析一:Spring与Dubbo整合源码分析一

 前言

 如何扫描被@Service,@Reference注解的对象?我们srping会扫描包括@controller @service等注解修饰的类,但是dubbo自定义的注解如何被spring扫描呢,首先我们来看dubbo注解@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.xxx")表示对指定包下的类进行扫描,主要进行配置文件的处理最终生成相应的bean。然后是@DubboComponentScan,扫描@Service,@Reference注解的对象放入spring容器,具体如下:

@EnableDubbo这个注解其中有@Import(DubboConfigConfigurationRegistrar.class),很关键,@Import是spring中比较巧妙的一个可以被用户扩展 srpingbean容器的一个注解,这个注解可以允许spring启动时候执行注解属性DubboConfigConfigurationRegistrar.class中的一个方法=》registerBeanDefinitions(),顾名思义注册用户自定义的beanDefinition,这样就把配置文件的信息进行扫描,具体细节:

     第一部分配置扫描成bean:

  1. 根据DubboConfigConfiguration.Single.class的定义来注册BeanDefinition,如果开启了multiple模式,则根据DubboConfigConfiguration.Multiple.class的定义来注册BeanDefinition
  2. 两者都是调用的registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses)方法
  3. 在registerBeans方法内,会利用Spring中的AnnotatedBeanDefinitionReader类来加载annotatedClasses参数所指定的类(上面所Single或Multiple类),Spring的AnnotatedBeanDefinitionReader类会识别annotatedClasses上的注解,然后开启解析annotatedClasses类上的注解
  4. 可以发现,不管是Single类,还是Multiple类,类上面定义的注解都是@EnableDubboConfigBindings,所以Spring会解析这个注解,在这个注解的定义上Import了一个DubboConfigBindingsRegistrar类,所以这是Spring会去调用DubboConfigBindingsRegistrar类的registerBeanDefinitions方法
  5. 在DubboConfigBindingsRegistrar类的registerBeanDefinitions方法中,会去取EnableDubboConfigBindings注解的value属性的值,该值是一个数组,数组中存的内容为@EnableDubboConfigBinding注解。此时DubboConfigBindingsRegistrar会去处理各个@EnableDubboConfigBinding注解,使用DubboConfigBindingRegistrar类的registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry)去处理各个@EnableDubboConfigBinding注解
  6.  attributes表示@EnableDubboConfigBinding注解中的参数对,比如prefix = "dubbo.application", type = ApplicationConfig.class
  7. 获取出对应当前@EnableDubboConfigBinding注解的prefix和AbstractConfig类,ApplicationConfig、RegistryConfig、ProtocolConfig等等都是AbstractConfig类的子类
  8. 从environment.getPropertySources()中获取对应的prefix的properties,相当于从Properties文件中获取对应prefix的属性,后面在生成了AplicationConfig类型的BeanDefinition之后,会把这些属性值赋值给对应的BeanDefinition,但是这里获取属性只是为了获取beanName
  9. 在生成Bean之前,需要确定Bean的名字,可以通过在Properties文件中配置相关的id属性,那么则对应的值就为beanName,否则自动生成一个beanName
  10. 对于Multiple模式的配置,会存在多个bean以及多个beanName
  11. 得到beanName之后,向Spring中注册一个空的BeanDefinition对象,并且向Spring中添加一个DubboConfigBindingBeanPostProcessor(Bean后置处理器),在DubboConfigBindingBeanPostProcessor中有一个构造方法,需要传入prefix和beanName。总结一下:一个AbstractConfig的子类会对应一个bean(Multiple模式下会有多个),每个bean对应一个DubboConfigBindingBeanPostProcessor后置处理器,至此,Spring扫描逻辑走完了。
  12. 接下来,Spring会根据生成的BeanDefinition生成一个对象,然后会经过DubboConfigBindingBeanPostProcessor后置处理器的处理。
  13. DubboConfigBindingBeanPostProcessor主要用来对其对应的bean进行属性赋值
  14. 首先通过DubboConfigBinder的默认实现类DefaultDubboConfigBinder,来从Properties文件中获取prefix对应的属性值,然后把这些属性值赋值给AbstractConfig对象中的属性
  15. 然后看AbstractConfig类中是否存在setName()方法,如果存在则把beanName设置进去

       这样一个AbstractConfig类的bean就生成好了,总结一下:Spring在启动时,会去生成ApplicationConfig、RegistryConfig、ProtocolConfig等等AbstractConfig子类的bean对象,然后从Properties文件中获取属性值并赋值到bean对象中去

    第二部分对象扫描成bean:

      DubboComponentScanRegistrar的registerBeanDefinitions方法中:

  1. 首先获得用户指定的扫描包路径
  2. 然后分别生成ServiceAnnotationBeanPostProcessor和ReferenceAnnotationBeanPostProcessor类的BeanDefinition,并注册到Spring中,注意这两个类看上去像,但完全不是一个层面的东西。
  3. ServiceAnnotationBeanPostProcessor是一个BeanDefinitionRegistryPostProcessor,是在Spring扫描过程中执行的。
  4. ReferenceAnnotationBeanPostProcessor的父类是AnnotationInjectedBeanPostProcessor,是一个InstantiationAwareBeanPostProcessorAdapter,是在Spring对容器中的bean进行依赖注入时使用的。

     当Spring根据BeanDefinition生成了实例对象后,就需要对对象中的属性进行赋值,此时会:

  1. 调用AnnotationInjectedBeanPostProcessor类中的postProcessPropertyValues方法,查找注入点,查找到注入点后就会进行属性注入,注入点分为被@Reference注解了的属性字段,被@Reference注解了的方法
  2. 调用AnnotationInjectedBeanPostProcessor类中的findFieldAnnotationMetadata方法查找属性注入点,返回类型为List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement>
  3. 调用AnnotationInjectedBeanPostProcessor类中的findAnnotatedMethodMetadata方法查找方法注入点,返回类型为List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement>
  4. 注解掉找到后,就调用InjectionMetadata的inject方法进行注入。
  5. 针对AnnotatedFieldElement,调用getInjectedObject方法得到注入对象injectedObject,然后通过反射field.set(bean, injectedObject);
  6. 针对AnnotatedMethodElement,调用getInjectedObject方法得到注入对象injectedObject,然后通过反射method.invoke(bean, injectedObject);
  7. 在getInjectedObject方法中,调用doGetInjectedBean方法得到注入对象,doGetInjectedBean方法在ReferenceAnnotationBeanPostProcessor类中提供了实现
  8. 根据@Reference注解中的参数信息与待注入的属性类型,生成一个serviceBeanName,查看在本应用的Spring容器中是否存在这个名字的bean,如果存在,则表示现在引入的服务就在本地Spring容器中
  9. 根据@Reference注解中的参数信息与待注入的属性类型,生成一个referenceBeanName
  10. 根据referenceBeanName、@Reference注解中的参数信息与待注入的属性类型生成一个ReferenceBean对象(注意,这里直接就是对象了,最终返回的就是这个对象的get方法的返回值
  11. 把ReferenceBean对象通过beanFactory注册到Spring中
  12. 那么ReferenceBean对象是怎么产生的呢?
  13. AnnotatedInterfaceConfigBeanBuilder类的build方法来生成这个ReferenceBean对象
  14. 先new ReferenceBean<Object>();得到一个ReferenceBean实例
  15. 然后调用configureBean(ReferenceBean实例);给ReferenceBean实例的属性进行赋值
  16. 调用preConfigureBean(attributes, ReferenceBean实例);,把Reference注解的参数值赋值给ReferenceBean实例,除开"application", "module", "consumer", "monitor", "registry"这几个参数
  17. 调用configureRegistryConfigs对ReferenceBean实例的registries属性进行赋值,通过@Reference注解中所配置的registry属性获得到值,然后根据该值从Spring容器中获得到bean
  18. 同样的,通过调用configureMonitorConfig、configureApplicationConfig、configureModuleConfig方法分别进行赋值
  19. 调用postConfigureBean方法对applicationContext、interfaceName、consumer、methods属性进行赋值
  20. 最后调用ReferenceBean实例的afterPropertiesSet方法
  21. ReferenceBean生成后了之后,就会调用ReferenceBean的get方法得到一个接口的代理对象,最终会把这个代理对象注入到属性中去
  22. 总结一下:ReferenceAnnotationBeanPostProcessor主要在Spring对容器中的Bean进行属性注入时进行操作,当Spring对一个Bean进行属性注入时,先查找@Reference的注入点,然后对注入点进行调用,在调用过程中,会根据属性类型,@Reference注解信息生成一个ReferenceBean,然后对ReferenceBean对象的属性进行赋值,最后调用ReferenceBean的get方法得到一个代理对象,最终把这个代理对象注入给属性。需要注意的是ReferenceBean的get()方法就是服务引入流程的入口。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值