?其中,我们使用 Springboot 版本是2.2.0 。
于是手动跟踪调试了下,发现某些后置处理器执行时,在解决它的依赖时,会去创建 dubbo 服务的 bean,然后就会创建 ApplicationConfig 对象了 。注意这个对象其实只是new了一下,所有属性都是默认值,并非来源于我们定义的 dubbo 配置文件 。
而我们定义的 dubbo 配置文件,是在 ApplicationConfig 中的 addIntoConfigManager 中注入的:
public abstract class AbstractConfig implements Serializable {...@PostConstructpublic void addIntoConfigManager() {ApplicationModel.getConfigManager().addConfig(this);}...}
其中,@PostConstruct 注解会由 CommonAnnotationBeanPostProcessor 这个后置处理器(继承自 InitDestroyAnnotationBeanPostProcessor)解析执行 。但很遗憾,此时它还没有被执行,因此也就没有把正确的dubbo配置注入进去,最终导致dubbo框架在校验时发现无效配置,继而报错 。
网上相关讨论及解决方案关于这类报错,网上也有不少讨论,如:
- No application config found or it's not a valid config!
- No registry config found or it's not a valid config!
- 同样的配置,2.7.3启动成功,2.7.6启动报错
自然,dubbo官方也注意到了这个问题,于是在3.x版本进行了改造,针对该问题做了优化,参见Dubbo 3 Spring相关优化 。
但3.x做了大量重构,如果我们不想升级,应该怎么办呢?其实根据上面提到的原因,我们可以自己定义一个后置处理器,拦截 dubbo 框架的 beans,并手动注入对应的配置 。本质上来说,将之前来不及执行的注入代码提到前面去 。这样,我们前面提到的「某些后置处理器执行时,在解决它的依赖时,会去创建 dubbo 服务的 bean,然后就会创建 ApplicationConfig 对象了」,就变成了「某些后置处理器执行时,在解决它的依赖时,会去创建 dubbo 服务的 bean,此时会被我们自定义的后置处理器拦截,并注入对应的dubbo配置,然后就会创建正确的 ApplicationConfig 对象」 。
具体做法为:
step1. 定义一个后置处理器,识别到 bean 属于 AbstractConfig 配置后,将其注入:
package com.xxx;import org.apache.dubbo.config.AbstractConfig;import org.apache.dubbo.rpc.model.ApplicationModel;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;public class DubboBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof AbstractConfig) {AbstractConfig abstractConfig = (AbstractConfig) bean;ApplicationModel.getConfigManager().addConfig(abstractConfig);}return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}}
step2. 定义一个 Initializer,并将刚才定义的 DubboBeanPostProcessor 注入:
package com.xxx;import org.springframework.context.ApplicationContextInitializer;import org.springframework.context.ConfigurableApplicationContext;public class DubboApplicationContextInitializerimplements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {applicationContext.getBeanFactory().addBeanPostProcessor(new DubboBeanPostProcessor());}}
step3. 把 DubboApplicationContextInitializer 注入到Spring框架中,可以采用多种方式 。
方式1. 直接在启动类注入:
@ImportResource(locations = {"classpath:dubbo.xml"})@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})public class Launcher extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(Launcher.class);springApplication.addInitializers(new DubboApplicationContextInitializer());springApplication.run(args);}}
经验总结扩展阅读
- 保单年检的意义和重要性
- 轻度感冒有什么症状
- 西安一码通和地铁乘车码有区别吗
- 刘备和曹操个人武力谁厉害
- cvt和自动挡有什么区别
- 骁龙870和天玑1200哪个玩游戏更好_骁龙870和天玑1200哪个好
- 华为p50pro和荣耀magic3pro哪个好_手机区别对比
- redmi watch和小米手表color哪款更值得买?
- 光遇b服和官服互通吗
- 如何做酥脆的面食