Dubbo源码---加载流程

629 阅读5分钟

简介

这一篇来分析下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服务启动后到加载流程,只是简单的做了个梳理,前面我们有讲过,会在后续的源码分析中,对各个阶段进行详细的讲解。