Spring-boot-2.6.3集成nacos报NoClassDefFoundError问题解决

报错

项目基于spring-boot-2.6.3,后来需要接入nacos作为注册中心,接入nacos后报错如下:
image.png
报错信息表明运行环境中找不到ConfigurationBeanFactoryMetadata这个类。

报错分析

从报错信息来看是项目启动过程中需要初始化ConfigurationPropertiesRebinderAutoConfiguration这个Bean,这个Bean引用了ConfigurationBeanFactoryMetadata这个类,这个类找不到(NoClassDefFoundError)。
首先来看一下ConfigurationBeanFactoryMetadata这个类,这个类出现在spring-boot这个包中,如下所示:
image.png
不过,在spring-boot-2.4.X及以上版本中,这个类被删掉了。
下面来看一下,报错项目的相关依赖版本:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.6.3</version>
   <relativePath/>
</parent>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>

项目上用的spring-boot版本是2.6.3,也就是说在该版本下,ConfigurationBeanFactoryMetadata这个类已经被删除了,项目启动过程中在初始化ConfigurationPropertiesRebinderAutoConfiguration这个bean(准确的说是初始化ConfigurationPropertiesRebinderAutoConfiguration的configurationPropertiesBeans这个方法返回的bean)的时候,由于找不到ConfigurationBeanFactoryMetadata这个类,就报了NoClassDefFoundError这个错误。

解决过程

网络上比较多的解决方法:

spring-boot版本降级

这个方法比较粗暴,也比较简单,既然2.4.X及以上版本把ConfigurationBeanFactoryMetadata这个类删除了,那么,把spring-boot降到2.3.X及以下版本,自然就找得到这个类了。如果采用这种办法,那么项目就无法接入spring-boot新版本的功能,项目spring-boot版本永远只能停留在低版本,除非等待nacos在新版中解决该问题。很显然这种办法很low。

手动加上ConfigurationBeanFactoryMetadata

既然新版本删除了org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata这个类,那么手动把它加到项目中去,理论上就可以解决这个问题。具体参考:
https://blog.csdn.net/demontxy/article/details/122187321
该解决方式很简单,就是在自己项目上新建一个包(org.springframework.boot.context.properties与ConfigurationBeanFactoryMetadata的包保持一致),然后在该包下新建一个类ConfigurationBeanFactoryMetadata类(保持和低版本,如spring-boot-2.3.X内的类一致),然后将该类的bean注入到Spring上下文,ConfigurationPropertiesRebinderAutoConfiguration这个类会从Spring容器中去取这个 bean:

@Bean
@ConditionalOnMissingBean(
    search = SearchStrategy.CURRENT
)
public ConfigurationPropertiesBeans configurationPropertiesBeans() {
    ConfigurationBeanFactoryMetadata metaData = (ConfigurationBeanFactoryMetadata)this.context.getBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class);
    ConfigurationPropertiesBeans beans = new ConfigurationPropertiesBeans();
    beans.setBeanMetaDataStore(metaData);
    return beans;
}

这种方法本人尝试过,依然会报异常,不过报的错是NoSuchBeanDefinitionException这个异常,表示Spring上下文没有找到ConfigurationBeanFactoryMetadata这个类的bean,目前猜测原因是bean加载顺序导致的,也就是说初始化ConfigurationPropertiesRebinderAutoConfiguration的configurationPropertiesBeans时,applicationContext(spring上下文)还没有初始化ConfigurationBeanFactoryMetadata这个类的bean。

改造nacos源码

这种方法是一般是由于引入如下nacos依赖引起的:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.3</version>
</parent>
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-discovery-spring-boot-starter</artifactId>
    <version>0.2.7</version>
</dependency>
<dependency>
		<groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-config-spring-boot-starter</artifactId>
    <version>0.2.7</version>
</dependency>

spring-boot是2.4.X及以上版本,引入nacos依赖以后,报NoClassDefFoundError错误:
image.png

具体原因是项目启动后,初始化NacosBootConfigurationPropertiesBinder这个bean时,会从Spring上下文中去取ConfigurationBeanFactoryMetadata这个类的bean:

private ConfigurationBeanFactoryMetadata beanFactoryMetadata;
private StandardEnvironment environment = new StandardEnvironment();

public NacosBootConfigurationPropertiesBinder(ConfigurableApplicationContext applicationContext) {
    super(applicationContext);
    this.beanFactoryMetadata = (ConfigurationBeanFactoryMetadata)applicationContext.getBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class);
}

由于spring-boot-2.6.3版本删除了ConfigurationBeanFactoryMetadata这个类,所以会报NoClassDefFoundError错误。
NacosBootConfigurationPropertiesBinder这个类出现在nacos-config-spring-boot-autoconfigure这个依赖包中:
image.png
首先需要下载nacos-spring-boot-project源码:
image.png
然后对NacosBootConfigurationPropertiesBinder类进行改造,改造目的主要是替换掉ConfigurationBeanFactoryMetadata这个类,然后修改版本号,接着重新打包,部署到maven私服,然后项目中引入改造后的版本,具体改造方法参考:https://blog.csdn.net/demontxy/article/details/122187321

我的项目及解决办法:

首先,项目依赖版本情况:

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.6.3</version>
   <relativePath/>
</parent>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency>

项目启动,初始化ConfigurationPropertiesRebinderAutoConfiguration的configurationPropertiesBeans时报错NoClassDefFoundError,原因上面提到过,就是spring 高版本(2.4.X及以上版本)中删除了ConfigurationBeanFactoryMetadata这个类。

@Bean
@ConditionalOnMissingBean(
    search = SearchStrategy.CURRENT
)
public ConfigurationPropertiesBeans configurationPropertiesBeans() {
    ConfigurationBeanFactoryMetadata metaData = (ConfigurationBeanFactoryMetadata)this.context.getBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class);
    ConfigurationPropertiesBeans beans = new ConfigurationPropertiesBeans();
    beans.setBeanMetaDataStore(metaData);
    return beans;
}

首先来看看ConfigurationPropertiesRebinderAutoConfiguration这个类,这个类来自于spring-cloud-context-2.0.4.RELEASE这个包,spring-cloud-context这个包来自于spring-cloud-starter-alibaba-nacos-config依赖包:
image.png
image.png
spring-cloud-context-2.0.4.RELEASE这个包版本比较低,适配于比较低的spring-boot版本。基于这个原因,猜测在更新的spring-cloud-context包(适配于比较高的spring-boot版本,比如2.5.X)中会删除对ConfigurationBeanFactoryMetadata这个类的依赖,因为高版本的spring-boot包删除了ConfigurationBeanFactoryMetadata这个类,那么与之兼容的spring-cloud版本也会去掉对这个类的依赖。

基于以上思路,要解决ConfigurationBeanFactoryMetadata这个类的NoClassDefFoundError报错,
可以将spring-cloud-starter-alibaba-nacos-discovery和spring-cloud-starter-alibaba-nacos-config的版本上级到较高版本,比如:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.1.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2021.0.1.0</version>
</dependency>

该版本的nacos包依赖的spring-cloud-context-3.1.1这个比较高的版本,在这个版本中ConfigurationPropertiesRebinderAutoConfiguration类去掉了对ConfigurationBeanFactoryMetadata这个类的依赖
image.png

另一方面,如果不想升级spring-cloud-starter-alibaba-nacos-discovery和spring-cloud-starter-alibaba-nacos-config的版本,也可以直接升级spring-cloud-context这个依赖包,毕竟NoClassDefFoundError报错是因为这个依赖包版本过低引起的,所以可以直接升级spring-cloud-context的版本到3.1.4。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-context</artifactId>
    <version>3.1.4</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.0.3.RELEASE</version>
    <exclusions>
       <exclusion>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.0.3.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
        </exclusion>
      </exclusions>
</dependency>
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
注:下文中的 *** 代表文件名中的组件名称。 # 包含: 中文-英文对照文档:【***-javadoc-API文档-中文(简体)-英语-对照版.zip】 jar包下载地址:【***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: 中文-英文对照文档,中英对照文档,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【***.jar中文文档.zip】,再解压其中的 【***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·本文档为双语同时展示,一行原文、一行译文,可逐行对照,避免了原文/译文来回切换的麻烦; ·有原文可参照,不再担心翻译偏差误导; ·边学技术、边学英语。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值