Dubbo与Spring的融合机制
我们都知道Dubbo可以与Spring进行融合,那是怎么进行融合的呢?
我先介绍一下官方文档中是如何实现与Spring融合的,然后再从底层分析一下。
Service注解暴露服务
增加应用配置信息
指定Spring扫描路径
Reference注解引用服务
增加应用配置信息
指定Spring扫描路径
调用服务
上面是整体融合Spring的案例,接下来分析 Service 注解和 Reference 注解是怎么实现的。
当用户使用注解 @DubboComponentScan 时,会激活 DubboComponentScanRegister ,同时生成 ServiceAnnotationBeanPostProcessor 和 ReferenceAnnotationBeanPostProcessor , ServiceAnnotationBeanPostProcessor 处理器实现了 BeanDefinitionRegistryPostProcessor 接口,Spring容器会在所有Bean注册之后回调 postProcessBeanDefinitionRegistry 方法。
在这个方法里先提取用户配置的扫描包名称,然后委托Spring对所有符合包名的class文件做字节码分析,然后扫描Dubbo的注解@Service作为过滤条件,将扫描的服务创建 BeanDefinitionHolder ,用于生成 ServiceBean 定义,最后注册 ServiceBean 的定义并做数据绑定和解析。
这时我们注册了 ServiceBean 的定义,但是还没有实例化。
ServicecBean 的结构如下:
InitializingBean
只包含 afterPropertiesSet() 方法,继承该接口的类,在初始化Bean的时候会执行该方法。在构造方法之后调用。
ApplicationContextAware
Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了 ApplicationContextAware 接口,Spring容器会在创建该Bean之后,自动调用该Bean的 setApplicationContextAware() 方法,调用该方法时,会将容器本身作为参数传给该方法。
ApplicationListener
当Spring容器初始化之后,会发布一个ContextRefreshedEvent事件,实现ApplicationListener接口的类,会调用 onApplicationEvent() 方法。
重要的接口主要是这几个,那么执行的先后顺序是怎样的呢?
如果某个类实现了ApplicationContextAware接口,会在类初始化完成后调用setApplicationContext()方法进行操作
首先会执行 ApplicationContextAware 中的 setApplicationContextAware() 方法。
这里主要是将Spring的上下文引用保存到 SpringExtensionFactory 中,里面有个set集合,保存所有的Spring上下文。这里实现了Dubbo与Spring容器的相连,在SPI机制中利用 ExtensionLoader.getExtension 生成扩展类时,会有一个依赖注入的过程,即调用 injectExtension() 方法,它会通过反射获取类的所有方法,然后遍历以set开头的方法,得到set方法的参数类型,再通过ExtensionFactory寻找参数类型相同的扩展类实例。
如果某个类实现了InitializingBean接口,会在类初始化完成后,并在setApplicationContext()方法执行完毕后,调用afterPropertiesSet()方法进行操作
然后会调用 InitializingBean 的 afterPropertiesSet() 方法。
主要是将Dubbo中的应用信息、注册信息、协议信息等设置到变量中。最后有个方法值得注意的是 isDelay 方法当返回true时,表示无需延迟导出;返回false时,表示需要延迟导出。
最后会调用 ApplicationListene 中的 onApplicationEvent 方法。
此时 ServiceBean 开始暴露。 具体的暴露流程之前已经介绍容量。
在Dubbo中处理 ReferenceBean 是通过 ReferenceAnnotionBeanPostProcessor 处理的,该类继承了 InstantiationAwareBeanPostProcessor ,用来解析@Reference注解并完成依赖注入。
InstatiationAwareBeanPostProcessor
postProcessBeforeInstantiation 方法: 在实例化目标对象执行之前,可以自定义实例化逻辑,如返回一个代理对象。
postProcessAfterInitialization 方法:Bean实例化完成后执行的后处理操作,所有初始化逻辑、装配逻辑之前执行。
postProcessPropertyValues 方法: 完成其他定制的一些依赖注入和依赖检查等,可以增加属性和属性值修改。
新版本出现了改动,采用 AnnotationInjectedBeanPostProcessor 来处理。
AnnotationInjectedBeanPostProcessor 是 ReferenceAnnotationBeanPostProcessor 的父类,它实现InstantiationAwareBeanPostProcessorAdapter的postProcessPropertyValues方法,这个是实例化的后置处理,这个方式是在注入属性时触发,就是要在注入@Reference的接口时候,要将接口封装成动态代理的实例注入到Spring容器中.
主要分为两步:
1) 获取类中标注的@Reference注解的字段和方法。
2)反射设置字段或方法对应的引用
最重要的是第二步,通过 inject 方法进行反射绑定。
里面最主要的就是对生成的ReferenceBean设置一个代理对象。
服务引用的触发时机有两个:
一种是ReferenceBean初始化的时候;另一种是ReferenceBean对应的服务被注入到其他类中时引用。