简介
这一篇来分析下Dubbo启动的执行流程,只做简单的分析,为后面具体的源码分析做一次简单的梳理(具体分析篇幅太太太长了。。。)。Dubbo服务的启动是始于Spring容器启动过程中,将Dubbo事件及监听器注册到Spring容器,而后在事件刷新到过程中执行Dubbo服务的启动。Dubbo服务启动的入口方法是DubboBootstrapApplicationListener的onApplicationContextEvent方法。onApplicationContextEvent是一个事件响应方法,该方法会在收到 Spring 上下文刷新事件后执行Dubbo服务启动操作,该方法如下:
源码分析
public void onApplicationContextEvent(ApplicationContextEvent event) {
// 判断事件类型,上下文刷新事件
if (event instanceof ContextRefreshedEvent) {
// 在这里执行dubbo服务的启动
onContextRefreshedEvent((ContextRefreshedEvent) event);
// 上下文关闭事件
} else if (event instanceof ContextClosedEvent) {
// 在这里执行dubbo服务的关闭
onContextClosedEvent((ContextClosedEvent) event);
}
}
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
private void onContextClosedEvent(ContextClosedEvent event) {
dubboBootstrap.stop();
}
从上述方法中可知在Spring上下文刷新事件中Dubbo启动执行,在Spring上下文关闭事件中关闭dubbo。
DubboBoostrap启动
public DubboBootstrap start() {
if (started.compareAndSet(false, true)) {
ready.set(false);
// 初始化
initialize();
// 1、导出dubbo服务
exportServices();
// 不仅仅是服务提供者注册
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// 2. 导出元数据服务
exportMetadataService();
// 3.如果需要,注册本地ServiceInstance
registerServiceInstance();
}
//处理引用dubbo服务
referServices();
// 异步导出
if (asyncExportingFutures.size() > 0) {
new Thread(() -> {
try {
this.awaitFinish();
} catch (Exception e) {
logger.warn(NAME + " exportAsync occurred an exception.");
}
// 设置启动状态
ready.set(true);
}).start();
// 非异步导出
} else {
// 设置启动状态
ready.set(true);
}
}
return this;
}
上述为DubboBootstrap启动流程。
初始化
public void initialize() {
if (!initialized.compareAndSet(false, true)) {
return;
}
// 初始化框架扩展
ApplicationModel.initFrameworkExts();
// 启动配置中心
startConfigCenter();
// 加载远程调用配置
loadRemoteConfigs();
// 校验通用配置
checkGlobalConfigs();
// @since 2.7.8
// 启动元数据中心
startMetadataCenter();
// 初始化元数据服务
initMetadataService();
// 初始化元数据服务导出
initMetadataServiceExports();
// 初始化事件监听器
initEventListener();
if (logger.isInfoEnabled()) {
logger.info(NAME + " has been initialized!");
}
}
初始化框架扩展
public static void initFrameworkExts() {
// 此处为获取扩展类实例,即从ExtensionLoader中获取其实例
Set<FrameworkExt> exts = ExtensionLoader.getExtensionLoader(FrameworkExt.class).getSupportedExtensionInstances();
for (FrameworkExt ext : exts) {
// 初始化FrameworkExt
ext.initialize();
}
}
该方法通过Dubbo SPI加载META-INF/dubbo/internal/org.apache.dubbo.common.context.FrameworkExt文件,获取扩展后并执行其初始化。
启动配置中心
private void startConfigCenter() {
// 如果未在environment及ConfigManager设置配置中心,且ConfigManager中添加了RegistryConfig,则将ConfigManager中的Registry设置为配置中心
useRegistryAsConfigCenterIfNecessary();
// 获取配置中心
Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
// 校验配置中心
if (CollectionUtils.isEmpty(configCenters)) {
ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
// 刷新ConfigCenterConfig
configCenterConfig.refresh();
if (configCenterConfig.isValid()) {
// 添加配置中心
configManager.addConfigCenter(configCenterConfig);
configCenters = configManager.getConfigCenters();
}
} else {
for (ConfigCenterConfig configCenterConfig : configCenters) {
// 刷新配置中心
configCenterConfig.refresh();
// 校验配置中心配置
ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
}
}
if (CollectionUtils.isNotEmpty(configCenters)) {
// 多配置中心管理类的实例
CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
for (ConfigCenterConfig configCenter : configCenters) {
// 将配置中心添加到多配置中心管理器
compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
}
environment.setDynamicConfiguration(compositeDynamicConfiguration);
}
// 刷新所有配置
configManager.refreshAll();
}
启动配置中心的代码代码逻辑很清晰,按步骤分为:获取ConfigCnenterConfig、刷新配置中心、多配置中心管理、刷新所有配置
加载远程调用配置
private void loadRemoteConfigs() {
// 将registry ids转换成RegistryConfig
List<RegistryConfig> tmpRegistries = new ArrayList<>();
Set<String> registryIds = configManager.getRegistryIds();
registryIds.forEach(id -> {
if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {
tmpRegistries.add(configManager.getRegistry(id).orElseGet(() -> {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setId(id);
// 刷新注册配置
registryConfig.refresh();
return registryConfig;
}));
}
});
// 添加注册配置(RegistryConfig)
configManager.addRegistries(tmpRegistries);
// 将protocol ids转换成ProtocolConfig
List<ProtocolConfig> tmpProtocols = new ArrayList<>();
Set<String> protocolIds = configManager.getProtocolIds();
protocolIds.forEach(id -> {
if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
tmpProtocols.add(configManager.getProtocol(id).orElseGet(() -> {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setId(id);
// protocolConfig刷新
protocolConfig.refresh();
return protocolConfig;
}));
}
});
// 添加协议配置(ProtocolConfig)
configManager.addProtocols(tmpProtocols);
}
加载远程通用配置的方法,做了两件事,一是将registry ids转换成RegsitryConfig并刷新,二是将protocol ids转换成ProtocolConfig并刷新。
校验通用配置
private void checkGlobalConfigs() {
// 校验ApplicationConfig(应用配置)
ConfigValidationUtils.validateApplicationConfig(getApplication());
// 校验MetadataReportConfig(元数据导出配置)
Collection<MetadataReportConfig> metadatas = configManager.getMetadataConfigs();
if (CollectionUtils.isEmpty(metadatas)) {
MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
// 刷新
metadataReportConfig.refresh();
if (metadataReportConfig.isValid()) {
configManager.addMetadataReport(metadataReportConfig);
metadatas = configManager.getMetadataConfigs();
}
}
if (CollectionUtils.isNotEmpty(metadatas)) {
for (MetadataReportConfig metadataReportConfig : metadatas) {
// 刷新
metadataReportConfig.refresh();
// 校验
ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
}
}
// 校验ProviderConfig(提供者配置)
Collection<ProviderConfig> providers = configManager.getProviders();
if (CollectionUtils.isEmpty(providers)) {
configManager.getDefaultProvider().orElseGet(() -> {
ProviderConfig providerConfig = new ProviderConfig();
configManager.addProvider(providerConfig);
// 刷新
providerConfig.refresh();
return providerConfig;
});
}
for (ProviderConfig providerConfig : configManager.getProviders()) {
ConfigValidationUtils.validateProviderConfig(providerConfig);
}
// 校验ConsumerConfig(消费者配置)
Collection<ConsumerConfig> consumers = configManager.getConsumers();
if (CollectionUtils.isEmpty(consumers)) {
configManager.getDefaultConsumer().orElseGet(() -> {
ConsumerConfig consumerConfig = new ConsumerConfig();
configManager.addConsumer(consumerConfig);
consumerConfig.refresh();
return consumerConfig;
});
}
for (ConsumerConfig consumerConfig : configManager.getConsumers()) {
ConfigValidationUtils.validateConsumerConfig(consumerConfig);
}
// 校验MonitoryConfig(监控配置)
ConfigValidationUtils.validateMonitorConfig(getMonitor());
// 校验MetricsConfig
ConfigValidationUtils.validateMetricsConfig(getMetrics());
// 校验ModuleConfig
ConfigValidationUtils.validateModuleConfig(getModule());
// 校验SslConfig
ConfigValidationUtils.validateSslConfig(getSsl());
}
通用配置校验,依次为ApplicationConfig、MetadataReportConfig、ProviderConfig、ConsumerConfig、MonitoryConfig、MetricsConfig、ModuleConfig、SslConfig。
启动元数据服务
private void startMetadataCenter() {
// 如果有需要,使用registry作为元数据中心
useRegistryAsMetadataCenterIfNecessary();
ApplicationConfig applicationConfig = getApplication();
String metadataType = applicationConfig.getMetadataType();
// FIXME, multiple metadata config support.
Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
if (CollectionUtils.isEmpty(metadataReportConfigs)) {
if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when 'metadata=remote' is enabled.");
}
return;
}
MetadataReportConfig metadataReportConfig = metadataReportConfigs.iterator().next();
// 校验
ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
if (!metadataReportConfig.isValid()) {
return;
}
// 初始化
MetadataReportInstance.init(metadataReportConfig.toUrl());
}
指定MetadataReportConfig并初始化。
初始化元数据服务
private void initMetadataService() {
this.metadataService = WritableMetadataService.getExtension(getMetadataType());
}
通过Dubbo SPI获取MetadataService
初始化元数据导出服务
private void initMetadataServiceExports() {
this.metadataServiceExporters = getExtensionLoader(MetadataServiceExporter.class).getSupportedExtensionInstances();
}
通过Dubbo SPI获取MetadataServiceExporter的列表
初始化事件监听器
private void initEventListener() {
// 将当前实例添加到侦听器中
addEventListener(this);
}
public DubboBootstrap addEventListener(EventListener<?> listener) {
eventDispatcher.addEventListener(listener);
return this;
}
将当前实例添加到监听器中
导出服务
private void exportServices() {
configManager.getServices().forEach(sc -> {
// TODO, compatible with ServiceConfig.export()
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
// 异步导出
if (exportAsync) {
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future<?> future = executor.submit(() -> {
sc.export();
exportedServices.add(sc);
});
asyncExportingFutures.add(future);
// 同步导出
} else {
// 导出
sc.export();
exportedServices.add(sc);
}
});
}
导出dubbo service,判断是同步还是异步导出。
导出元数据服务
private void exportMetadataService() {
metadataServiceExporters
.stream()
.filter(this::supports)
.forEach(MetadataServiceExporter::export);
}
注册服务实例
private void registerServiceInstance() {
if (CollectionUtils.isEmpty(getServiceDiscoveries())) {
return;
}
// 获取ApplicationConfig
ApplicationConfig application = getApplication();
// 获取应用名称
String serviceName = application.getName();
// 获取元数据服务导出的URL
URL exportedURL = selectMetadataServiceExportedURL();
// 获取host
String host = exportedURL.getHost();
// 获取port
int port = exportedURL.getPort();
// 实例化ServiceInstance
ServiceInstance serviceInstance = createServiceInstance(serviceName, host, port);
// 准备注册ServiceInstance
preRegisterServiceInstance(serviceInstance);
// 获取发现的Service并注册到ServiceInstance
getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
}
引用服务
private void referServices() {
if (cache == null) {
cache = ReferenceConfigCache.getCache();
}
configManager.getReferences().forEach(rc -> {
// TODO, compatible with ReferenceConfig.refer()
ReferenceConfig referenceConfig = (ReferenceConfig) rc;
referenceConfig.setBootstrap(this);
if (rc.shouldInit()) {
if (referAsync) {
CompletableFuture<Object> future = ScheduledCompletableFuture.submit(
executorRepository.getServiceExporterExecutor(),
() -> cache.get(rc)
);
asyncReferringFutures.add(future);
} else {
cache.get(rc);
}
}
});
}
总结
上述就是Dubbo服务启动后到加载流程,只是简单的做了个梳理,前面我们有讲过,会在后续的源码分析中,对各个阶段进行详细的讲解。