Dubbo学习之DubboConfigInitEvent

本文详细解析了SpringBoot中Dubbo的配置初始化过程,包括如何借助DubboConfigInitEvent事件启动配置Bean的实例化,以及ModuleDeployer的准备工作,如配置中心和元数据中心的启动。通过分析关键步骤,展示了Dubbo如何与SpringBoot集成以实现服务的自动配置。
摘要由CSDN通过智能技术生成

相关阅读

简介

本文基于Spring Boot 2.6.6dubbo-spring-boot-starter 3.0.6环境。

Dubbo借助DubboConfigInitEvent事件完成初始化,事件DubboConfigInitEvent的处理主要分为两步:

  1. 实例化DubboConfigBeanInitializerDubboConfigBeanInitializer是Dubbo用于初始化配置Bean,Dubbo的配置Bean需要在所有BeanPostProcessor注册以后才可以被初始化;
  2. 准备ModuleDeployer,用于发布Module

借助Spring Boot的事件发布机制,Dubbo实现了事件DubboConfigInitEvent,在ReferenceAnnotationBeanPostProcessor.postProcessBeanFactory中被发布(此时还不存在ApplicationEventMulticaster,故缓存到早期事件earlyApplicationEvents),在AbstractApplicationContext.registerListeners(在AbstractApplicationContext.registerBeanPostProcessors之后)中作为早期事件被处理;

Demo

测试环境基于Spring Boot 2.6.6;
核心依赖:

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>3.0.6</version>
</dependency>

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-zookeeper</artifactId>
    <version>3.0.6</version>
</dependency>

核心配置参数:

server:
  port: 8080
dubbo:
  application:
    id: dubbo-provider
    name: dubbo-provider
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    port: 20880
  scan:
    base-packages: dubbo.producer.demo.service.impl

DubboConfigInitEvent

发布DubboConfigInitEvent

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法中,会执行容器中所有BeanFactoryPostProcessor的处理,执行顺序大致如下:

  1. 实现了PriorityOrderedBeanDefinitionRegistryPostProcessor
  2. 实现了OrderedBeanDefinitionRegistryPostProcessor
  3. 剩下的BeanDefinitionRegistryPostProcessor
  4. 实现了PriorityOrderedBeanFactoryPostProcessor
  5. 实现了OrderedBeanFactoryPostProcessor
  6. 剩下的BeanFactoryPostProcessor

注意:BeanFactoryPostProcessor的获取途径有两种:代码直接添加和配置(代码配置或者文件配置),这里分析的执行顺序没有考虑这两种途径的区别;

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessorPriorityOrdered,所以它会先执行其postProcessBeanDefinitionRegistry逻辑,从而引入了DubboAutoConfiguration自动配置类,由上文可知,DubboAutoConfiguration自动配置会调用到DubboBeanUtils.registerCommonBeans,该方法内会注册ReferenceAnnotationBeanPostProcessorRootBeanDefinition
ReferenceAnnotationBeanPostProcessor实现了BeanFactoryPostProcessorOrdered,故在第五步时,会引入ReferenceAnnotationBeanPostProcessor并执行其postProcessBeanFactory方法;
ReferenceAnnotationBeanPostProcessor.postProcessBeanFactory方法中会发布DubboConfigInitEvent事件,代码如下:

applicationContext.publishEvent(new DubboConfigInitEvent(applicationContext));

此时,AbstractApplicationContext中还不存在ApplicationEventMulticaster,所以还无法真正发布事件,便先缓存到earlyApplicationEvents中,等初始化ApplicationEventMulticaster后再发布事件;
AbstractApplicationContext执行initApplicationEventMulticaster完成初始化ApplicationEventMulticaster后,便可以发布事件了,紧接着执行registerListeners,代码如下:

protected void registerListeners() {
    // 添加已存在的ApplicationListener
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 添加存在的ApplicationListener BeanName
    // 此时包含:org.apache.dubbo.config.spring.context.DubboConfigApplicationListener
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 发布缓存的早期事件
    // 此时包含DubboConfigInitEvent
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

处理DubboConfigInitEvent

ApplicationEventApplicationEventMulticaster.multicastEvent,默认实现为SimpleApplicationEventMulticaster,其代码如下:

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    // 获取支持本事件的ApplicationListener
    // 支持DubboConfigInitEvent:DubboConfigApplicationListener
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        // 执行监听器
        doInvokeListener(listener, event);
    }
}

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        // 处理事件
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        // 异常处理
        ...
    }
}

getApplicationListeners方法中会将支持DubboConfigInitEventDubboConfigApplicationListener实例化返回,然后执行其onApplicationEvent,代码如下:

public void onApplicationEvent(DubboConfigInitEvent event) {
    if (nullSafeEquals(applicationContext, event.getSource())) {
        // 如果已经初始化过,则无需再初始化
        if (initialized.compareAndSet(false, true)) {
            // 初始化配置Bean
            initDubboConfigBeans();
        }
    }
}

private void initDubboConfigBeans() {
    if (applicationContext.containsBean(DubboConfigBeanInitializer.BEAN_NAME)) {
        // 实例化DubboConfigBeanInitializer
        // DubboConfigBeanInitializer的RootBeanDefinition在DubboBeanUtils.registerCommonBeans中注册,由DubboAutoConfiguration触发
        applicationContext.getBean(DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
    } else {
        logger.warn("Bean '" + DubboConfigBeanInitializer.BEAN_NAME + "' was not found");
    }

    // ModuleDeployer初始化
    moduleModel.getDeployer().prepare();
}

DubboConfigBeanInitializer

DubboConfigBeanInitializer实现了接口InitializingBean,故实例化时会调用其afterPropertiesSet方法,代码如下:

public void afterPropertiesSet() throws Exception {
    init();
}

private void init() {
    // 如果已经初始化过,则无需再初始化
    if (initialized.compareAndSet(false, true)) {
        // 实例化ReferenceBeanManager
        // ReferenceBeanManager的RootBeanDefinition在DubboBeanUtils.registerCommonBeans中注册,由DubboAutoConfiguration触发
        referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
        try {
            // 初始化配置Bean
            prepareDubboConfigBeans();
            // 初始化ReferenceBean
            referenceBeanManager.prepareReferenceBeans();
        } catch (Throwable e) {
            throw new FatalBeanException("Initialization dubbo config beans failed", e);
        }
    }
}

private void prepareDubboConfigBeans() {
    logger.info("loading dubbo config beans ...");

    // 加载各种配置Bean,并注册到configManager
    loadConfigBeansOfType(ApplicationConfig.class, configManager);
    loadConfigBeansOfType(RegistryConfig.class, configManager);
    loadConfigBeansOfType(ProtocolConfig.class, configManager);
    loadConfigBeansOfType(MonitorConfig.class, configManager);
    loadConfigBeansOfType(ConfigCenterBean.class, configManager);
    loadConfigBeansOfType(MetadataReportConfig.class, configManager);
    loadConfigBeansOfType(MetricsConfig.class, configManager);
    loadConfigBeansOfType(SslConfig.class, configManager);

    // 加载Module配置Bean,并注册到moduleConfigManager
    loadConfigBeansOfType(ModuleConfig.class, moduleModel.getConfigManager());
    loadConfigBeansOfType(ProviderConfig.class, moduleModel.getConfigManager());
    loadConfigBeansOfType(ConsumerConfig.class, moduleModel.getConfigManager());

    // 加载ConfigCenterBean
    List<ConfigCenterBean> configCenterBeans = configManager.loadConfigsOfTypeFromProps(ConfigCenterBean.class);
    for (ConfigCenterBean configCenterBean : configCenterBeans) {
        String beanName = configCenterBean.getId() != null ? configCenterBean.getId() : "configCenterBean";
        beanFactory.initializeBean(configCenterBean, beanName);
    }

    logger.info("dubbo config beans are loaded.");
}

private void loadConfigBeansOfType(Class<? extends AbstractConfig> configClass, AbstractConfigManager configManager) {
    // 获取容器中configClass类型的BeanName
    String[] beanNames = beanFactory.getBeanNamesForType(configClass, true, false);
    for (String beanName : beanNames) {
        // 实例化configClass
        AbstractConfig configBean = beanFactory.getBean(beanName, configClass);
        // 注册configBean
        configManager.addConfig(configBean);
    }
}

本次测试环境下,由于未注册相关配置Bean的RootBeanDefinition,所以prepareDubboConfigBeans并没有加载任何Bean;
接下来就是执行referenceBeanManager.prepareReferenceBeans(),代码如下:

public void prepareReferenceBeans() throws Exception {
    // 设置初始化标识
    // 这样后续添加ReferenceBean就可以立即初始化
    initialized = true;
    for (ReferenceBean referenceBean : getReferences()) {
        // 初始化提前添加的ReferenceBean
        initReferenceBean(referenceBean);
    }
}

至此,DubboConfigBeanInitializer实例化就结束了,Dubbo借助其完成相关Bean(如果存在的话)的实例化;

ModuleDeployer

DubboConfigApplicationListener.initDubboConfigBeans方法中,除了实例化DubboConfigBeanInitializer外,还有很重要的操作,即moduleModel.getDeployer().prepare(),此处ModuleDeployer实现类为DefaultModuleDeployer,其prepare方法代码如下:

public void prepare() {
    // 先初始化Application
    applicationDeployer.initialize();
    // 再初始化Module
    this.initialize();
}

准备工作分为两步:

  1. 初始化Application;
  2. 初始化Module;

初始化Application

applicationDeployer的实现为DefaultApplicationDeployer,其initialize方法代码如下:

public void initialize() {
    if (initialized) {
        // 如果已经初始化过,则直接退出
        return;
    }

    synchronized (startLock) {
        // 再次确认是否已经完成初始化,确保并发安全
        if (initialized) {
            return;
        }
        // 注册DubboShutdownHook
        registerShutdownHook();

        // 开启配置中心
        startConfigCenter();

        // 加载Application相关配置
        loadApplicationConfigs();

        // 初始化相关ModuleModel
        initModuleDeployers();

        // 开启元数据中心
        startMetadataCenter();

        // 设置初始化标识
        initialized = true;

        if (logger.isInfoEnabled()) {
            logger.info(getIdentifier() + " has been initialized!");
        }
    }
}

开启配置中心

代码如下:

private void startConfigCenter() {

    // 从配置文件中加载ApplicationConfig信息
    // 配置参数前缀为:dubbo.application
    configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);

    if (StringUtils.isBlank(applicationModel.getModelName())) {
        applicationModel.setModelName(applicationModel.tryGetApplicationName());
    }

    // 从配置文件中加载ConfigCenterConfig信息
    // 配置参数前缀为:dubbo.config-center
    configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class);

    // 如果没有有效ConfigCenterConfig,则使用默认RegistryConfig作为ConfigCenterConfig
    // RegistryConfig也会从配置文件中加载
    // 配置参数前缀为:dubbo.registry
    useRegistryAsConfigCenterIfNecessary();

    // 如果此时还没有ConfigCenterConfig,那就会创建一个出来
    Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
    if (CollectionUtils.isEmpty(configCenters)) {
        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
        configCenterConfig.setScopeModel(applicationModel);
        configCenterConfig.refresh();
        ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
        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) {
            environment.updateExternalConfigMap(configCenter.getExternalConfiguration());
            environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());

            // 此时会创建DynamicConfiguration实例,连接该configCenter
            compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
        }
        environment.setDynamicConfiguration(compositeDynamicConfiguration);
    }
}

加载Application相关配置

代码如下:

private void loadApplicationConfigs() {
    // 从配置文件中加载配置信息
    configManager.loadConfigs();
}


// ConfigManager.java
public void loadConfigs() {
    // ApplicationConfig已经在DefaultApplicationDeployer.startConfigCenter中加载过了,故会跳过
    loadConfigsOfTypeFromProps(ApplicationConfig.class);

    // 从配置文件中加载MonitorConfig信息
    // 配置参数前缀为:dubbo.monitor
    loadConfigsOfTypeFromProps(MonitorConfig.class);

    // 从配置文件中加载MetricsConfig信息
    // 配置参数前缀为:dubbo.metrics
    loadConfigsOfTypeFromProps(MetricsConfig.class);

    // 从配置文件中加载ProtocolConfig信息
    // 配置参数前缀为:dubbo.protocol
    loadConfigsOfTypeFromProps(ProtocolConfig.class);

    // RegistryConfig已经在DefaultApplicationDeployer.startConfigCenter中加载过了,故会跳过
    loadConfigsOfTypeFromProps(RegistryConfig.class);

    // 从配置文件中加载MetadataReportConfig信息
    // 配置参数前缀为:dubbo.metadata-report
    loadConfigsOfTypeFromProps(MetadataReportConfig.class);

    // config centers has bean loaded before starting config center
    //loadConfigsOfTypeFromProps(ConfigCenterConfig.class);

    // 刷新配置如果存在的话
    refreshAll();

    // 校验配置
    // 1. 某配置不存在但是必须就会创建该配置
    // 2. 配置存在ConfigValidator,则调用ConfigValidator.validate进行校验
    // 3. 同一个端口不能有重复的ProtocolConfig
    checkConfigs();

    if (StringUtils.isBlank(applicationModel.getModelName())) {
        applicationModel.setModelName(applicationModel.getApplicationName());
    }
}

初始化相关ModuleModel

代码如下:

private void initModuleDeployers() {
    // 确保默认Module存在
    // 不存在就会创建
    applicationModel.getDefaultModule();
    // copy modules and initialize avoid ConcurrentModificationException if add new module
    List<ModuleModel> moduleModels = new ArrayList<>(applicationModel.getModuleModels());
    for (ModuleModel moduleModel : moduleModels) {
        // 初始化相关Module
        moduleModel.getDeployer().initialize();
    }
}

开启元数据中心

代码如下:

private void startMetadataCenter() {

    // 如果没有有效MetadataCenter,则使用默认RegistryConfig作为ConfigCenterConfig
    useRegistryAsMetadataCenterIfNecessary();

    ApplicationConfig applicationConfig = getApplication();

    String metadataType = applicationConfig.getMetadataType();
    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 metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);
    List<MetadataReportConfig> validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size());
    for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
        ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
        if (!metadataReportConfig.isValid()) {
            logger.warn("Ignore invalid metadata-report config: " + metadataReportConfig);
            continue;
        }
        validMetadataReportConfigs.add(metadataReportConfig);
    }
    metadataReportInstance.init(validMetadataReportConfigs);
    if (!metadataReportInstance.inited()) {
        throw new IllegalStateException(String.format("%s MetadataConfigs found, but none of them is valid.", metadataReportConfigs.size()));
    }
}

初始化Module

DefaultModuleDeployer.initialize方法代码如下:

public void initialize() throws IllegalStateException {
    if (initialized) {
        // 如果已经初始化过,则直接退出
        return;
    }

    synchronized (this) {
        // 再次确认是否已经完成初始化,确保并发安全
        if (initialized) {
            return;
        }
        
        // 加载配置:ProviderConfig、ConsumerConfig、ModuleConfig
        loadConfigs();

        ModuleConfig moduleConfig = moduleModel.getConfigManager().getModule().orElseThrow(() -> new IllegalStateException("Default module config is not initialized"));
        exportAsync = Boolean.TRUE.equals(moduleConfig.getExportAsync());
        referAsync = Boolean.TRUE.equals(moduleConfig.getReferAsync());

        // start in background
        background = moduleConfig.getBackground();
        if (background == null) {
            // compatible with old usages
            background = isExportBackground() || isReferBackground();
        }

        // 设置初始化标识
        initialized = true;
        if (logger.isInfoEnabled()) {
            logger.info(getIdentifier() + " has been initialized!");
        }
    }
}

加载配置

代码如下:

private void loadConfigs() {
    // load module configs
    moduleModel.getConfigManager().loadConfigs();
    moduleModel.getConfigManager().refreshAll();
}


// ModuleConfigManager.java
public void loadConfigs() {
    // 从配置文件中加载ProviderConfig信息
    // 配置参数前缀为:dubbo.provider
    loadConfigsOfTypeFromProps(ProviderConfig.class);

    // 从配置文件中加载ConsumerConfig信息
    // 配置参数前缀为:dubbo.consumer
    loadConfigsOfTypeFromProps(ConsumerConfig.class);

    // 从配置文件中加载ModuleConfig信息
    // 配置参数前缀为:dubbo.module
    loadConfigsOfTypeFromProps(ModuleConfig.class);

    // 校验配置
    // 1. 某配置不存在但是必须就会创建该配置
    // 2. 配置存在ConfigValidator,则调用ConfigValidator.validate进行校验
    checkDefaultAndValidateConfigs(ProviderConfig.class);
    checkDefaultAndValidateConfigs(ConsumerConfig.class);
    checkDefaultAndValidateConfigs(ModuleConfig.class);
}

public void refreshAll() {
    // 刷新配置

    getModule().ifPresent(ModuleConfig::refresh);
    getProviders().forEach(ProviderConfig::refresh);
    getConsumers().forEach(ConsumerConfig::refresh);

    getReferences().forEach(ReferenceConfigBase::refresh);
    getServices().forEach(ServiceConfigBase::refresh);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值