本文基于dubbo 2.7.5版本代码
文章目录
在本文分析一下DubboBootstrap的initialize方法。
private void initialize() {
if (!initialized.compareAndSet(false, true)) {
return;//initialize方法只能初始化一次
}
ApplicationModel.iniFrameworkExts();//初始化FrameworkExt实现类,这里会调用Environment的initialize方法
startConfigCenter();//
useRegistryAsConfigCenterIfNecessary();//
startMetadataReport();//
loadRemoteConfigs();//
checkGlobalConfigs();//
initMetadataService();//
initMetadataServiceExporter();//
initEventListener();//
if (logger.isInfoEnabled()) {
logger.info(NAME + " has been initialized!");
}
}
ApplicationModel.iniFrameworkExts()
初始化FrameworkExt实现类。
Environment是FrameworkExt实现类。Environment的initialize方法首先从ConfigManager获取默认的配置中心对象ConfigCenterConfig,如果存在ConfigCenterConfig对象,那么将ConfigCenterConfig的externalConfiguration和appExternalConfiguration两个属性值设置到Environment的名字一致的两个属性上。
startConfigCenter
该方法从ConfigManager中获得的所有的ConfigCenterConfig对象。然后访问配置中心的配置,将这些配置保存到Environment对象,最后使用这些配置更新ApplicationConfig、MonitorConfig、ModuleConfig等对象的属性。
配置中心可以有多个,在获取配置的时候,顺次访问每个配置中心,配置保存到本地时后访问的配置中心配置会覆盖之前的配置数据。
useRegistryAsConfigCenterIfNecessary
如果在方法startConfigCenter中,从ConfigManager里面没有找到ConfigCenterConfig对象,那么在本方法里面,会判断注册中心配置对象RegistryConfig的useAsConfigCenter值:
1、如果useAsConfigCenter=null或者true,那么就将注册中心作为配置中心,接下来创建对象ConfigCenterConfig,并将RegistryConfig中的地址、协议、用户名等信息设置到ConfigCenterConfig中,然后将ConfigCenterConfig对象添加到ConfigManager,最后再执行一次startConfigCenter。
2、对于其他的useAsConfigCenter值,dubbo跳过该注册中心RegistryConfig。
useAsConfigCenter默认为null。从上面可以看出,dubbo可以配置多个注册中心和配置中心。
startMetadataReport
该方法主要是创建对象MetadataReport,建立与元数据中心的连接。
MetadataReportConfig是元数据中心,用于存储dubbo的元数据信息,这是后增加一个功能。后面的文章在介绍元数据中心。dubbo可以不配置元数据中心。
ApplicationConfig的metadataType字段用于指定元数据中心的类型,有两个值:remote(远程)和local(本地)。该方法首先检查metadataType,如果类型是remote,那么必须配置MetadataReportConfig。
然后该方法使用SPI加载MetadataReportFactory对象,之后通过MetadataReportFactory对象创建MetadataReport对象,MetadataReport对象在构造方法中建立与元数据中心的连接。dubbo使用MetadataReport访问元数据中心。
元数据中心可以配置多个,但是只会使用其中一个,代码如下,dubbo根据MetadataReportConfig配置的address中的协议匹配对应的MetadataReportFactory实现类。
Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
MetadataReportConfig metadataReportConfig = metadataReportConfigs.iterator().next();
MetadataReportInstance.init(metadataReportConfig.toUrl());//只会使用集合的第一个
loadRemoteConfigs
创建RegistryConfig和ProtocolConfig对象,并设置其属性。
该方法首先从Environment对象的appExternalConfigurationMap和externalConfigurationMap字段中获取所有的ProtocolConfig和RegistryConfig的id值,根据id值创建对应的RegistryConfig和ProtocolConfig对象。之后使用Environment对象设置RegistryConfig和ProtocolConfig对象的各个属性。以RegistryConfig的创建为例,代码如下:
List<RegistryConfig> tmpRegistries = new ArrayList<>();
Set<String> registryIds = configManager.getRegistryIds();//获取所有的id
//遍历id
registryIds.forEach(id -> {
if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {
tmpRegistries.add(configManager.getRegistry(id).orElseGet(() -> {//id对应的RegistryConfig不存在,则创建
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setId(id);
registryConfig.refresh();//使用Environment对象的属性值初始化RegistryConfig对象
return registryConfig;
}));
}
});
//将RegistryConfig添加到ConfigManager对象
configManager.addRegistries(tmpRegistries);
从configManager中获取id值,是搜索字段前缀查找的,RegistryConfig的id对应的前缀是:dubbo.registries.,ProtocolConfig的id对应的前缀是:dubbo.protocols.。
checkGlobalConfigs
检查各个配置对象的各个属性设置的值是否合法,检查内容包括是否有非法字符,长度是否超长。
检查的对象有:ApplicationConfig、ConfigCenterConfig、MetadataReportConfig、MonitorConfig、MetricsConfig、ModuleConfig、SslConfig。
initMetadataService
通过SPI加载WritableMetadataService实现类,实现类的名字是由ApplicationConfig类的metadataType字段指定的。
WritableMetadataService继承了接口MetadataService。WritableMetadataService后续文章再分析。
initMetadataServiceExporter
initMetadataServiceExporter创建ConfigurableMetadataServiceExporter对象,initMetadataService方法加载的WritableMetadataService对象作为其属性。ConfigurableMetadataServiceExporter的作用是将WritableMetadataService对象以dubbo服务的形式对外提供服务,这样客户端便可以使用dubbo协议访问MetadataService接口里面的方法。
initMetadataServiceExporter仅仅是创建ConfigurableMetadataServiceExporter对象,对外发布服务是在DubboBootstrap的start方法里面完成的。
initEventListener
本方法是初始化的最后一个方法。该方法是将DubboBootstrap对象注册为监听器。
dubbo有自己实现的事件发布机制,其接口是EventDispatcher,默认实现是DirectEventDispatcher。事件发布机制其他文章介绍。
DubboBootstrap监听所有dubbo的org.apache.dubbo.event.Event事件。
这里可能大家会有一个疑问,对于服务端来说,调用initialize方法是在容器事件发布后,此时各个配置对象都已经创建完毕,在initialize中使用没有什么问题,但是客户端调用该方法的时候,是在对ReferenceBean对象执行bean后处理器,换句话说spring此时还在对ReferenceBean对象创建的过程中,那么dubbo如何保证客户端启动的时候initialize中需要的配置对象都创建完毕了呢?大家可以看《dubbo解析-客户端启动入口》里面提到一个方法doGetInjectedBean,该方法创建ReferenceBean对象,但创建其实委托给ReferenceBeanBuilder,在new ReferenceBean()后,会执行ReferenceBeanBuilder的方法prepareDubboConfigBeans,该方法代码如下:
private void prepareDubboConfigBeans() {
beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class);
beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class);
beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class);
beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class);
beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class);
beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class);
beansOfTypeIncludingAncestors(applicationContext, SslConfig.class);
}
beansOfTypeIncludingAncestors方法获取spring容器中第二个入参要求类型的所有bean对象。dubbo就是通过这个方法保证了在调用DubboBootstrap.initialize方法之前,所有的配置对象都已经创建完毕。