聊聊dubbo的DubboApplicationContextInitializer

麦克斯韦妖
• 阅读 2443

本文主要研究一下dubbo的DubboApplicationContextInitializer

DubboApplicationContextInitializer

dubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/DubboApplicationContextInitializer.java

public class DubboApplicationContextInitializer implements ApplicationContextInitializer, Ordered {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        overrideBeanDefinitions(applicationContext);
    }

    private void overrideBeanDefinitions(ConfigurableApplicationContext applicationContext) {
        applicationContext.addBeanFactoryPostProcessor(new OverrideBeanDefinitionRegistryPostProcessor());
        applicationContext.addBeanFactoryPostProcessor(new DubboConfigBeanDefinitionConflictProcessor());
    }

    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }

}
  • DubboApplicationContextInitializer实现了ApplicationContextInitializer, Ordered接口,initialize方法执行overrideBeanDefinitions,它往applicationContext添加了OverrideBeanDefinitionRegistryPostProcessor、DubboConfigBeanDefinitionConflictProcessor;getOrder返回的是HIGHEST_PRECEDENCE

OverrideBeanDefinitionRegistryPostProcessor

dubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/OverrideBeanDefinitionRegistryPostProcessor.java

public class OverrideBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        registerInfrastructureBean(registry, BEAN_NAME, DubboConfigBeanCustomizer.class);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
}
  • OverrideBeanDefinitionRegistryPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,其postProcessBeanDefinitionRegistry方法调用了BeanRegistrar.registerInfrastructureBean方法注册DubboConfigBeanCustomizer

BeanRegistrar

dubbo-2.7.3-sources.jar!/org/apache/dubbo/config/spring/util/BeanRegistrar.java

public class BeanRegistrar {

    /**
     * Register Infrastructure Bean
     *
     * @param beanDefinitionRegistry {@link BeanDefinitionRegistry}
     * @param beanType               the type of bean
     * @param beanName               the name of bean
     */
    public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry,
                                                  String beanName,
                                                  Class<?> beanType) {

        if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
        }

    }

}
  • registerInfrastructureBean在beanDefinitionRegistry没有该beanDefinition的情况下会注册BeanDefinition.ROLE_INFRASTRUCTURE的bean

DubboConfigBeanCustomizer

dubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/DubboConfigBeanCustomizer.java

@Deprecated
class DubboConfigBeanCustomizer extends NamePropertyDefaultValueDubboConfigBeanCustomizer {

    @Override
    public void customize(String beanName, AbstractConfig dubboConfigBean) {
        boolean valid = isValidPropertyName(dubboConfigBean, beanName);
        if (valid) {
            super.customize(beanName, dubboConfigBean);
        }
    }

    private boolean isValidPropertyName(AbstractConfig dubboConfigBean, String propertyValue) {
        boolean valid = true;
        String propertyName = "name";
        // AbstractConfig.checkName(String,String)
        Method method = findMethod(AbstractConfig.class, "checkName", String.class, String.class);
        try {
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            if (BeanUtils.getPropertyDescriptor(dubboConfigBean.getClass(), propertyName) != null) {
                invokeMethod(method, null, propertyName, propertyValue);
            }
        } catch (IllegalStateException e) {
            valid = false;
        }

        return valid;
    }
}
  • DubboConfigBeanCustomizer继承了NamePropertyDefaultValueDubboConfigBeanCustomizer,其customize方法会先校验propertyName,在valid的情况下才会执行父类的customize方法

DubboConfigBeanDefinitionConflictProcessor

dubbo-spring-boot-project-2.7.3/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/DubboConfigBeanDefinitionConflictProcessor.java

public class DubboConfigBeanDefinitionConflictProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private BeanDefinitionRegistry registry;

    private Environment environment;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        this.registry = registry;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        resolveUniqueApplicationConfigBean(registry, beanFactory);
    }

    /**
     * Resolve the unique {@link ApplicationConfig} Bean
     *
     * @param registry    {@link BeanDefinitionRegistry} instance
     * @param beanFactory {@link ConfigurableListableBeanFactory} instance
     * @see EnableDubboConfig
     */
    private void resolveUniqueApplicationConfigBean(BeanDefinitionRegistry registry,
                                                    ConfigurableListableBeanFactory beanFactory) {

        this.environment = beanFactory.getBean(ENVIRONMENT_BEAN_NAME, Environment.class);

        String[] beansNames = beanNamesForTypeIncludingAncestors(beanFactory, ApplicationConfig.class);

        if (beansNames.length < 2) { // If the number of ApplicationConfig beans is less than two, return immediately.
            return;
        }

        // Remove ApplicationConfig Beans that are configured by "dubbo.application.*"
        Stream.of(beansNames)
                .filter(this::isConfiguredApplicationConfigBeanName)
                .forEach(registry::removeBeanDefinition);

        beansNames = beanNamesForTypeIncludingAncestors(beanFactory, ApplicationConfig.class);

        if (beansNames.length > 1) {
            throw new IllegalStateException(String.format("There are more than one instances of %s, whose bean definitions : %s",
                    ApplicationConfig.class.getSimpleName(),
                    Stream.of(beansNames)
                            .map(registry::getBeanDefinition)
                            .collect(Collectors.toList()))
            );
        }
    }

    private boolean isConfiguredApplicationConfigBeanName(String beanName) {
        boolean removed = BeanFactoryUtils.isGeneratedBeanName(beanName)
                // Dubbo ApplicationConfig id as bean name
                || Objects.equals(beanName, environment.getProperty("dubbo.application.id"));

        if (removed) {
            if (logger.isWarnEnabled()) {
                logger.warn("The {} bean [ name : {} ] has been removed!", ApplicationConfig.class.getSimpleName(), beanName);
            }
        }

        return removed;
    }


    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}
  • DubboConfigBeanDefinitionConflictProcessor实现了BeanDefinitionRegistryPostProcessor, Ordered接口;postProcessBeanFactory方法会执行resolveUniqueApplicationConfigBean,校验同一个beanDefinition是否会有多个实例,有的话会抛出IllegalStateException;getOrder返回的是LOWEST_PRECEDENCE

小结

DubboApplicationContextInitializer实现了ApplicationContextInitializer, Ordered接口,initialize方法执行overrideBeanDefinitions,它往applicationContext添加了OverrideBeanDefinitionRegistryPostProcessor、DubboConfigBeanDefinitionConflictProcessor;getOrder返回的是HIGHEST_PRECEDENCE

doc

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
捉虫大师 捉虫大师
4年前
dubbo 2.7应用级服务发现踩坑小记
本文已收录https://github.com/lkxiaolou/lkxiaolou欢迎star。背景本文记录最近一位读者反馈的dubbo2.7.x中应用级服务发现的问题,关于dubbo应用级服务发现的相关介绍可以参考之前的文章,这里不再赘述。读者反馈他们在基于dubbo2.7应用级服务发现开发dubbo网关,根据文章《dubbo应用级服务发现初
Wesley13 Wesley13
4年前
java中比较两个时间的差值
项目背景1.某篇文稿的发布时间是publishDate,例如:2020072118:00:41。2.现要求判断该篇文稿的发布时间是否在近30天之内。publicstaticlongdayDiff(DatecurrentDate,DatepublishDate){LongcurrentTimecurrentDat
Easter79 Easter79
4年前
springcloud知识点总结
一.SpringCloud面试题口述1.SpringCloud和DubboSpringCloud和Dubbo都是现在主流的微服务架构SpringCloud是Apache旗下的Spring体系下的微服务解决方案Dubbo是阿里系的分布式服务治理框架从技术维度上,其实SpringCloud远远的超过Dubbo,Dubbo本身只是实现
Wesley13 Wesley13
4年前
eclipse中不能找到dubbo.xsd解决方法
使用dubbo时遇到问题:org.xml.sax.SAXParseException: schema\_reference.4: Failed to read schema document 'http://code.alibabatech.com/schema/dubbo/dubbo.xsd', because 1) could not f
捉虫大师 捉虫大师
4年前
聊聊dubbo协议2
在中介绍了attachments在consumer和provider间的传递情况,有个疑问没有给出答案。为什么2.7.x版本的dubbo不支持provider端向consumer端回传隐式参数呢?今天的续集将揭晓答案。抓包确定是provider没发还是consumer丢掉以下测试基于dubbo2.7.6版本在provider端加入下面的代码
捉虫大师 捉虫大师
4年前
聊聊dubbo协议
协议协议通俗易懂地解释就是通信双方需要遵循的约定。我们了解的常见的网络传输协议有tcp、udp、http等。再到我们常用的基础组件,一般来说client端与server端也有相应的协议,如redis、mysql、zookeeper等都是各自约定的私有协议,同样今天标题中的dubbo协议也是一种私有协议,他们都是应用层协议,基于tcp或udp设计。
Stella981 Stella981
4年前
Rpc框架dubbo
接上一篇dubboserver之后,再来看一下dubboclient是如何工作的。dubbo提供者服务示例,其结构是这样的!dubbo://192.168.11.6:20880/com.alibaba.dubbo.demo.DemoService?anyhosttrue&applicationdemoprovider&dubbo
Stella981 Stella981
4年前
Dubbo协议及序列化
Dubbo是Alibaba开源的分布式服务框架远程调用框架,在网络间传输数据,就需要通信协议和序列化。一通信协议Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的,默认也是用的dubbo协议。先介绍几种常见的协议:1\.
Stella981 Stella981
4年前
GoFramework框架简介(四)dubbo篇
框架中dubbo配置说明:Provider端配置如下:<dubbo:protocolname"dubbo"host"${dubbo.host}"port"${dubbo.port}"/<!服务提供者filter,在Provider上尽量多配置Consumer端属性,配置的覆盖规则:1)
Stella981 Stella981
4年前
Dubbo之服务暴露
!(https://oscimg.oschina.net/oscnet/up4596697d7918a914b39348df311c6366353.png)前言本文Dubbo使用版本2.7.5Dubbo通过使用dubbo:service配置或@service在解析完配置后进行服务暴露,供服务消费者消费。Dubbo的