报错
项目基于spring-boot-2.6.3,后来需要接入nacos作为注册中心,接入nacos后报错如下:
报错信息表明运行环境中找不到ConfigurationBeanFactoryMetadata这个类。
报错分析
从报错信息来看是项目启动过程中需要初始化ConfigurationPropertiesRebinderAutoConfiguration这个Bean,这个Bean引用了ConfigurationBeanFactoryMetadata这个类,这个类找不到(NoClassDefFoundError)。
首先来看一下ConfigurationBeanFactoryMetadata这个类,这个类出现在spring-boot这个包中,如下所示:
不过,在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)publicConfigurationPropertiesBeansconfigurationPropertiesBeans(){ConfigurationBeanFactoryMetadata metaData =(ConfigurationBeanFactoryMetadata)this.context.getBean(ConfigurationBeanFactoryMetadata.BEAN_NAME,ConfigurationBeanFactoryMetadata.class);ConfigurationPropertiesBeans beans =newConfigurationPropertiesBeans();
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错误:
具体原因是项目启动后,初始化NacosBootConfigurationPropertiesBinder这个bean时,会从Spring上下文中去取ConfigurationBeanFactoryMetadata这个类的bean:
privateConfigurationBeanFactoryMetadata beanFactoryMetadata;privateStandardEnvironment environment =newStandardEnvironment();publicNacosBootConfigurationPropertiesBinder(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这个依赖包中:
首先需要下载nacos-spring-boot-project源码:
然后对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)publicConfigurationPropertiesBeansconfigurationPropertiesBeans(){ConfigurationBeanFactoryMetadata metaData =(ConfigurationBeanFactoryMetadata)this.context.getBean(ConfigurationBeanFactoryMetadata.BEAN_NAME,ConfigurationBeanFactoryMetadata.class);ConfigurationPropertiesBeans beans =newConfigurationPropertiesBeans();
beans.setBeanMetaDataStore(metaData);return beans;}
首先来看看ConfigurationPropertiesRebinderAutoConfiguration这个类,这个类来自于spring-cloud-context-2.0.4.RELEASE这个包,spring-cloud-context这个包来自于spring-cloud-starter-alibaba-nacos-config依赖包:

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这个类的依赖
另一方面,如果不想升级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>
版权归原作者 青青子衣衿 所有, 如有侵权,请联系我们删除。