前言
- 上篇博客: Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理主要介绍了Dubbo注解版本的服务提供者中如何利用spring的扩展将服务注册到spring中去的。本次,我们总结下Dubbo加载配置的流程
一、Dubbo配置类
-
根据RPC原理,服务提供者得找一个地方存储服务信息,服务消费者得从某个地方消费服务。按照这样的逻辑,我们还要了解下Dubbo注解版本的一些基本配置是如何加载的。根据官网提供的
dubbo-demo-annotation-provider
模块中的Application.java文件。我们可以看到有一个静态内部类,而它内部维护了一个叫registryConfig的bean。根据官网的如下信息: 以及上篇博客提到的@EnableDubboConfig
注解的作用,它就是根据是否在dubbo.properties配置相关的配置然后去实例化相关的配置bean,若我们所有的配置都以java config的方式来配置的话,那这个注解基本上没啥用了,因为这个注解导入的DubboConfigBindingRegistrar和DubboConfigBindingsRegistrar扩展器中,会从配置文件中读取当前要实例化bean的配置前缀对应的配置信息,若读取的配置为空,则取消当前bean的配置
,具体代码如下:// prefix的值就是分别为: dubbo.application、dubbo.registry等等 Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix); 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; }
然后我们大胆猜测,当我们配置dubbo.application.name时,在Dubbo一定有一个叫ApplicationConfig的类来存储当前应用的名称(就像spring的spring.application.name一样)。于是我们修改ProviderConfiguration类为如下内容:
@Configuration @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider") @PropertySource("classpath:/spring/dubbo-provider.properties") static class ProviderConfiguration { @Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress("zookeeper://192.168.111.146:2181"); return registryConfig; } @Bean public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); applicationConfig.setName("dubbo-demo-annotation-provider-from-ProviderConfiguration"); return applicationConfig; } }
并重启服务提供者类,查看控制台输出的日志,可以发现注册在zookeeper中的服务对应的应用名也进行了修改。
[06/04/20 13:37:17:015 CST] main INFO config.AbstractConfig: [DUBBO] Export dubbo service org.apache.dubbo.demo.DemoService to local registry url : injvm://127.0.0.1/org.apache.dubbo.demo.DemoService?anyhost=true&application=dubbo-demo-annotation-provider-from-ProviderConfiguration&bean.name=ServiceBean:org.apache.dubbo.demo.DemoService&bind.ip=真实ip地址&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=17180®ister=true&release=&side=provider×tamp=1586151436848, dubbo version: , current host: 真实ip地址
既然,Dubbo每个配置类对应的是一个bean,那这个bean会不会实现spring的各种扩展呢?于是我们对如下类挨个进行检查:
纳尼,只有ConfigCenterBean稍微有点扩展,它实现了ApplicationContextAware, DisposableBean, EnvironmentAware三个接口,讲道理,这三个接口跟操作spring环境对象有关,压根不能影响加载配置的流程。看来配置类并没有什么扩展逻辑。同样的,在上篇博客介绍**@EnableDubboConfig注解时,有提到DubboConfigBindingBeanPostProcessor
, 它是一个专门管理Dubbo配置的一个后置处理器,它一共实现了BeanPostProcessor, InitializingBean两个接口。(好家伙,偷偷的注册,还有这么多功能,看我怎么把你识破). 看到这两个接口应该能明白这个后置处理器要做什么事了,它会首先调用InitializingBean的afterPropertiesSet
然后再调用BeanPostProcessor**的postProcessBeforeInitialization
, 然后再调用postProcessAfterInitialization
。(还好我记得pring bean初始化流程,哈哈)
二、DubboConfigBindingBeanPostProcessor的afterPropertiesSet方法
- 源码如下:
@Override public void afterPropertiesSet() throws Exception { // 先从spring中去获取DubboConfigBinder类型的bean,若spring中 // 没有维护,则自己手动创建默认的配置绑定器: DefaultDubboConfigBinder // 并绑定至当前对象中 initDubboConfigBinder(); // 从spring bean中拿到@EnableDubboConfigBinding注解导入的 // 自定义配置bean: NamePropertyDefaultValueDubboConfigBeanCustomizer initConfigBeanCustomizers(); }
- 所以大致可以了解,此方法就是初始化当前bean内部的一些属性(其实我很好奇为什么不让spring来自动装配它。。。),方便为后面的Dubbo配置提供条件
三、DubboConfigBindingBeanPostProcessor的postProcessBeforeInitialization方法
- 源码如下:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 它只对内部维护的beanName感兴趣,此beanName叫org.apache.dubbo.config.ProtocolConfig#0 // 看了下DubboConfigBindingBeanPostProcessor对beanName的处理,发现只有构造方法有赋值。因为是在DubboConfigBindingRegistrar.java中设置了构造方法的参数, 指定了让spring使用哪个构造器进行实例化对象 if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) { AbstractConfig dubboConfig = (AbstractConfig) bean; bind(prefix, dubboConfig); customize(beanName, dubboConfig); } return bean; }
- 此方法的具体作用就是将传入bean(ProtocolConfig)绑定配置,因为创建出来的dubbo配置bean里面内部的属性是空的,此方法执行完后,protocolConfig里面的属性就被填充了(会从JVM系统配置、当前系统配置环境、classpath中的properties文件中去取值)。
- 至此,Dubbo将默认的配置类的属性填充了。但要注意,不是所有的dubbo配置类都会走上面的流程。在上篇博客中有提到,当没有手动添加dubbo配置类给spring的话eg: 如下:
@Bean public RegistryConfig registryConfig() { RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress("zookeeper://192.168.111.146:2181"); return registryConfig; }
,dubbo会添加默认的配置类的bean。
四、总结
- 综上所述: 若没有手动的配置Dubbo内置的一些bean的话,会统一交给
DubboConfigBindingRegistrar
去注册,通过DubboConfigBindingRegistrar
注册有个特点,每个配置bean(eg: ProtocolConfig)会对应一个DubboConfigBindingBeanPostProcessor
, 并通过它来获取所有的配置文件JVM系统配置、当前系统配置环境、classpath中的properties
去取配置,并填充bean中的属性 - 注意: 官网中提供了配置的加载流程: http://dubbo.apache.org/zh-cn/docs/user/configuration/configuration-load-process.html, 但是就目前源码来看并没有看到从注册中心去配置的流程,以后再继续完善此部分的文档。
- I am a slow walker, but I never walk backwards.