背景介绍

最近把dubbo的版本从2.7.3升级到2.7.15时,遇到一个报错 No application config found or it's not a valid config! ,对应的异常栈为:

Caused by: java.lang.IllegalStateException: No application config found or it's not a valid config! Please add <dubbo:application name="..." /> to your spring config.
at org.apache.dubbo.config.utils.ConfigValidationUtils.validateApplicationConfig(ConfigValidationUtils.java:419) ~[dubbo-2.7.15.jar:2.7.15]
at org.apache.dubbo.config.bootstrap.DubboBootstrap.checkGlobalConfigs(DubboBootstrap.java:539) ~[dubbo-2.7.15.jar:2.7.15]
at org.apache.dubbo.config.bootstrap.DubboBootstrap.initialize(DubboBootstrap.java:525) ~[dubbo-2.7.15.jar:2.7.15]
at org.apache.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:244) ~[dubbo-2.7.15.jar:2.7.15]
at org.apache.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:206) ~[dubbo-2.7.15.jar:2.7.15]
at org.apache.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:68) ~[dubbo-2.7.15.jar:2.7.15]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:171) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1818) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1266) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:260) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:454) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:543) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:513) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:653) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:224) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:334) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1429) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:400) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1287) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:874) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:778) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:528) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:91) ~[spring-aop-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:109) ~[spring-aop-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:92) ~[spring-aop-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:101) ~[spring-aop-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:251) ~[spring-aop-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1141) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1114) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:506) ~[spring-beans-5.2.0.RELEASE.jar:5.2.0.RELEASE]
... 12 more

  

​其中,我们使用 Springboot 版本是2.2.0。

于是手动跟踪调试了下,发现某些后置处理器执行时,在解决它的依赖时,会去创建 dubbo 服务的 bean,然后就会创建 ApplicationConfig 对象了。注意这个对象其实只是new了一下,所有属性都是默认值,并非来源于我们定义的 dubbo 配置文件。

而我们定义的 dubbo 配置文件,是在 ApplicationConfig 中的 addIntoConfigManager 中注入的:

    public abstract class AbstractConfig implements Serializable {
... @PostConstruct
public void addIntoConfigManager() {
ApplicationModel.getConfigManager().addConfig(this);
} ...
}

  

其中,@PostConstruct 注解会由 CommonAnnotationBeanPostProcessor 这个后置处理器(继承自 InitDestroyAnnotationBeanPostProcessor)解析执行。但很遗憾,此时它还没有被执行,因此也就没有把正确的dubbo配置注入进去,最终导致dubbo框架在校验时发现无效配置,继而报错。

网上相关讨论及解决方案

关于这类报错,网上也有不少讨论,如:

简单总结起来,由于dubbo没有一个固定的初始化时机,而是与 ReferenceBean 等 dubbo 框架中的 beans 初始化相关。 如果它们被过早初始化,导致某些 BeanPostProcessor 尚未被执行,就会出现dubbo配置丢失的问题。

自然,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 { @Override
public 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 DubboApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override
public 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);
}
}

方式2. 在 resources 的 META-INF 目录下配置 spring.factories 文件并写入:

org.springframework.context.ApplicationContextInitializer=com.xxx.DubboApplicationContextInitializer

  

一个 dubbo 和 springboot 的兼容性问题的更多相关文章

  1. Dubbo整合Springboot框架

    本文使用的是alibaba的Dubbo. Dubbo整合Springboot可以分为四步: 第一步:首先需要了解Dubbo官方给的建议,至少有三个工程: 接口工程:主要存实体bean和业务接口 服务提 ...

  2. 从头开始搭建一个dubbo+zookeeper平台

    本篇主要是来分享从头开始搭建一个dubbo+zookeeper平台的过程,其中会简要介绍下dubbo服务的作用. 首先,看下一般网站架构随着业务的发展,逻辑越来越复杂,数据量越来越大,交互越来越多之后 ...

  3. 搭建一个dubbo+zookeeper平台

    本篇主要是来分享从头开始搭建一个dubbo+zookeeper平台的过程,其中会简要介绍下dubbo服务的作用. 首先,看下一般网站架构随着业务的发展,逻辑越来越复杂,数据量越来越大,交互越来越多之后 ...

  4. 第一个dubbo程序

    Dubbo是一个高性能服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案,使得应用可通过高性能RPC实现服务的输出和输入功能,和Spring框架可以无缝集成. 作为一个 ...

  5. 第一章 第一个dubbo项目

    为了安全:服务启动的ip全部使用10.10.10.10 版本: dubbo:2.5.5 重要的网址: dubbo的github:https://github.com/alibaba/dubbo dub ...

  6. What?一个 Dubbo 服务启动要两个小时!

    前言 前几天在测试环境碰到一个非常奇怪的与 dubbo 相关的问题,事后我在网上搜索了一圈并没有发现类似的帖子或文章,于是便有了这篇. 希望对还未碰到或正在碰到的朋友有所帮助. 现象 现象是这样的,有 ...

  7. dubbo+zookeeper+springboot简单示例

    目录 dubbo+zookeeper+springboot简单示例 zookeeper安装使用 api子模块 生产者producer 消费者consumer @(目录) dubbo+zookeeper ...

  8. Dubbo与SpringBoot的结合

    前言 这段时间在接触分布式的内容,因为公司的技术栈是 dubbo ,所以我顺其自然地选择了 dubbo 作为我学习的框架. 看了任务清单,这篇文章应该是在6天前出来的,但是因为实习等等的一些事情耽误了 ...

  9. 一个简单的SpringBoot入门程序

    1. 使用IDEA构建Maven项目 <?xml version="1.0" encoding="UTF-8"?> <project xmln ...

随机推荐

  1. else语句

    else的搭配 与else语句配合使用有三种情况 if ...: else: if条件表达式不成立的时候执行else 注意else还可以与while循环和for循环组合在一起(这是一个全新的知识) 注 ...

  2. ROS机械臂 Movelt 学习笔记3 | kinect360相机(v1)相关配置

    目标是做一个机械臂视觉抓取的demo,在基地里翻箱倒柜,没有找到学长所说的 d435,倒是找到了一个老古董 kinect 360. 前几天就已经在旧电脑上配置好了,现在记录在新电脑上的配置过程. 1. ...

  3. react 吸顶实现

    今天获取到一个需求,其实就是吸顶的需求,页面下滑,某一块dom隐藏时发生吸顶现象.这种特效其实老生常谈了,但是在这次做的时候,突发奇想,能否将其做成一个 hook ,从而实现出传递ref即可使得 do ...

  4. 丽泽普及2022交流赛day16 社论

    这场比较平凡吧 . 省流: http://zhengruioi.com/contest/1087 目录 目录 A. Gene 题面 题解 算法一(正解) 算法二 B. Fight 题面 题解 算法一( ...

  5. css基础04

    所有浮动都是贴着浮动的.一左一右的话就毫无联系了. 浮动元素和标准流是两个级别了,浮起来了,后面的人会补上空缺的位置,让其他标准流的盒子占有. 很容易形成叠加效果,(蓝色的标准流会上去补上浮动的位置, ...

  6. React报错之Property 'X' does not exist on type 'HTMLElement'

    正文从这开始~ 总览 在React中,当我们试图访问类型为HTMLElement 的元素上不存在的属性时,就会发生Property 'X' does not exist on type 'HTMLEl ...

  7. placeholder 设置换行三种方式

    在 html 中编写代码时保留代码换行 <textarea name="" id="" cols="30" rows="10 ...

  8. linux 磁盘io利用率高,分析的正确姿势

    一.背景简介 作为一个DBA难免不了会遇到性能问题,那么我们遇到性能问题该如何进行排查呢?例如我们在高并发的业务下,出现业务响应慢,处理时间长我们又该如何入手进行排查,本片文章将分析io高的情况下如何 ...

  9. 【springcloud】环境搭建与Rest使快速上手

    SpringCloud环境搭建 --- Rest使用 个人主页:https://www.cnblogs.com/xbudian/ 今天来到SpringCloud的学习,我们从spring boot微服 ...

  10. 048_末晨曦Vue技术_处理边界情况之使用$root访问根实例

    处理边界情况之使用$root访问根实例 点击打开视频教程 在每个 new Vue 实例的子组件中,其根实例可以通过 $root property 进行访问. 例如,在这个根实例中: src\main. ...