上一章我们的服务已经注册到spring容器中并完成实例化了,那么spring在实例化完成之后,就会进行一个最终的刷新操作,即方法
finishRefresh
在这里会发布
ContextRefreshedEvent
事件。dubbo的
DubboDeployApplicationListener
实现了
ApplicationListener
那么就会执行到
onApplicationEvent
方法 ,上代码
@Override
public void onApplicationEvent(ApplicationContextEvent event) {
if (nullSafeEquals(applicationContext, event.getSource())) {
if (event instanceof ContextRefreshedEvent) {
//处理ContextRefreshedEvent事件
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
}
进一步看一下onContextRefreshedEvent方法
//这里拿到就是DefaultModuleDeployer
ModuleDeployer deployer = moduleModel.getDeployer();
Assert.notNull(deployer, "Module deployer is null");
// 执行DefaultModuleDeployer的start方法
Future future = deployer.start();
继续start方法
@Override
public Future start() throws IllegalStateException {
// 这个方法其实在第一章中我们忽略的DubboSpringInitializer.initialize(registry),
//这里注册了reference的注解处理器,完成后会发布一个初始化事件,然后会执行到initialize,
applicationDeployer.initialize();
return startSync();
}
这里我们来提前了解一下应用发布器的initialize方法。主要看一下几个方法
//注册关闭钩子
registerShutdownHook();
//开启配置中心
startConfigCenter();
//加载配置
loadApplicationConfigs();
//初始化模块发布器,就是循环调用模块发布器的initialize方法
initModuleDeployers();
//如果配置了prometheus,会初始化这2项
initMetricsReporter();
initMetricsService();
//开启元数据中心
startMetadataCenter();
先来看看startConfigCenter方法,在这个方法里面,需要关注一下
loadConfigsOfTypeFromProps
这个方法 ,它将类名转化为dubbo前缀的配置,从properties中获取对应的值,startConfigCenter方法会先加载
ApplicationConfig
的配置 ,再加载
ConfigCenterConfig
的配置,然后执行
useRegistryAsConfigCenterIfNecessary
(
useRegistryAsConfigCenterIfNecessary
逻辑是判断是否配置了配置中心,有直接用,没有就用注册中心构造出一个配置中心,也就是端口,协议,地址等的一些赋值,可以看
registryAsConfigCenter
这个方法 。)最后会从配置中心远程拉取配置,分别放到
environment
不同的位置,这里需要看看
environment
了 。
Environment
继承自
LifecycleAdapter
所以在初始化的时候会执行
initialize
方法,这个是dubbo扩展加载器决定的,可以跟一下上一章提到的扩展加载器。
initialize
方法如下
//可以看到,不同的配置dubbo分开保存了
public void initialize() throws IllegalStateException {
if (initialized.compareAndSet(false, true)) {
//加载dubbo配置文件,可以看refresh方法,
// 先从JVM获取dubbo.properties.file配置文件,
// 没有从环境变量指定的dubbo.properties.file配置文件
// 如果都未指定,默认为dubbo.properties
this.propertiesConfiguration = new PropertiesConfiguration(scopeModel);
//保存系统JVM参数的配置
this.systemConfiguration = new SystemConfiguration();
//保存系统环境变量的配置
this.environmentConfiguration = new EnvironmentConfiguration();
//保存从远程配置中心的全局配置获取对应配置
this.externalConfiguration = new InmemoryConfiguration("ExternalConfig");
//保存从远程配置中心的应用配置获取对应配置
this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig");
//保存应用内的配置
this.appConfiguration = new InmemoryConfiguration("AppConfig");
//加载迁移配置,3.1默认已经移除,可以配置dubbo.migration-file.enable=true使生效,迁移规则可以看https://dubbo.apache.org/zh/docs/v3.0/advanced/migration-invoker/
loadMigrationRule();
}
}
上面开启了注册中心加载了一些配置,接下来我们看看loadApplicationConfigs方法,这里调用了
configManager.loadConfigs()
方法加载各种配置了,复制一下代码,loadConfigsOfTypeFromProps的逻辑上面提了一下,看下面代码都不需要注释,很好理解了。
loadConfigsOfTypeFromProps(ApplicationConfig.class);
// load dubbo.monitors.xxx
loadConfigsOfTypeFromProps(MonitorConfig.class);
// load dubbo.metrics.xxx
loadConfigsOfTypeFromProps(MetricsConfig.class);
// load multiple config types:
// load dubbo.protocols.xxx
loadConfigsOfTypeFromProps(ProtocolConfig.class);
// load dubbo.registries.xxx
loadConfigsOfTypeFromProps(RegistryConfig.class);
// load dubbo.metadata-report.xxx
loadConfigsOfTypeFromProps(MetadataReportConfig.class);
// config centers has bean loaded before starting config center
//loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
//调用上面加载的所有config的refresh方法,将值赋值到对应的属性变量。
refreshAll();
checkConfigs();
加载完成配置后,我们直接来看startMetadataCenter元数据中心,其他几项先忽略。
//如果未配置元数据中心的地址等配置则使用注册中心的地址等配置做为元数据中心的配置
useRegistryAsMetadataCenterIfNecessary();
//获取应用的配置信息
ApplicationConfig applicationConfig = getApplication();
//获取元数据类型,通过dubbo.application.metadataType配置 默认local ,可配置remote
String metadataType = applicationConfig.getMetadataType();
// 配置了remote,需要有元数据中心,不然会抛异常
Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
if (CollectionUtils.isEmpty(metadataReportConfigs)) {
if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
throw new IllegalStateException("No MetadataConfig found, Metadata Center address is required when 'metadata=remote' is enabled.");
}
return;
}
MetadataReportInstance metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);
List<MetadataReportConfig> validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size());
for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
validMetadataReportConfigs.add(metadataReportConfig);
}
//初始化元数据,这里只是构造了MetadataReport,并没有去往数据中心写数据
metadataReportInstance.init(validMetadataReportConfigs);
useRegistryAsMetadataCenterIfNecessary方法逻辑
先从缓存中查询元数据配置,配置存在则直接返回,
没有则查询所有可用的默认注册中心列表,多注册中心遍历→选符合条件的注册中心→注册中心配置RegistryConfig映射转换为元数据中心配置类型MetadataReportConfig 映射 →将元数据中心配置存储在配置缓存中方便后续使用
接下里看看metadataReportInstance.init初始化方法,初始化方法我们主要关注
MetadataReportFactory
来看一下实现类,
当然这三个实现类都继承自
AbstractMetadataReportFactory
AbstractMetadataReportFactory
实现了
MetadataReportFactory
接口 。三个实现类都实现了
AbstractMetadataReportFactory的 createMetadataReport
方法,在init方法中调用
metadataReportFactory.getMetadataReport*(*url*)*
方法。进而调用到
createMetadataReport
,我们看一下
ZookeeperMetadataReportFactory
的
createMetadataReport
方法如下:
@Override
public MetadataReport createMetadataReport(URL url) {
return new ZookeeperMetadataReport(url, zookeeperTransporter);
}
ZookeeperMetadataReport
构造函数前面都是拼一些参数,最后
zookeeperTransporter.connect(url);
建立了一个连接,这样就可以和Zookeeper通信了。
到这里我们的元数据中心已经准备完成。整个模块发布器也初始化完成了。