Spring-boot-2.6.3 integrates nacos to solve the problem of NoClassDefFoundError

Report an error

The project is based on spring-boot-2.6.3, and later needs to be connected to nacos as the registration center. After connecting to nacos, the error is reported as follows: The
image.png
error message indicates that the ConfigurationBeanFactoryMetadata class cannot be found in the running environment.

Error analysis

Judging from the error message, it is necessary to initialize the ConfigurationPropertiesRebinderAutoConfiguration Bean during the project startup process. This Bean refers to the ConfigurationBeanFactoryMetadata class, which cannot be found (NoClassDefFoundError).
First, let’s take a look at the ConfigurationBeanFactoryMetadata class. This class appears in the spring-boot package, as shown below:
image.png
However, in spring-boot-2.4.X and above, this class has been deleted.
Let’s take a look at the relevant dependency versions of the error reporting project:

<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>

The spring-boot version used in the project is 2.6.3, which means that in this version, the ConfigurationBeanFactoryMetadata class has been deleted. During the project startup process, the ConfigurationPropertiesRebinderAutoConfiguration bean is initialized (to be precise, the configurationPropertiesBeans method of initializing ConfigurationPropertiesRebinderAutoConfiguration returns bean), because the ConfigurationBeanFactoryMetadata class cannot be found, the NoClassDefFoundError error is reported.

Resolution process

There are many solutions on the Internet:

spring-boot version downgrade

This method is rough and simple. Since the ConfigurationBeanFactoryMetadata class has been deleted in versions 2.4. If this approach is adopted, the project will not be able to access the functions of the new version of spring-boot, and the project's spring-boot version will always stay at a lower version unless it waits for nacos to solve the problem in the new version. Obviously this method is very low.

Manually add ConfigurationBeanFactoryMetadata

Since the new version has deleted the org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata class, manually adding it to the project can theoretically solve this problem. Specific reference:
https://blog.csdn.net/demontxy/article/details/122187321
The solution is very simple, that is, create a new package on your own project (org.springframework.boot.context.properties is consistent with the package of ConfigurationBeanFactoryMetadata ), then create a new class ConfigurationBeanFactoryMetadata class under the package (keep it consistent with the classes in lower versions, such as spring-boot-2.3. Get this bean from:

@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;
}

I have tried this method, but it still reports an exception, but the error reported is NoSuchBeanDefinitionException, which means that the Spring context does not find the bean of the ConfigurationBeanFactoryMetadata class. The current guess is that the reason is caused by the bean loading order, that is to say, when initializing the configurationPropertiesBeans of ConfigurationPropertiesRebinderAutoConfiguration , applicationContext (spring context) has not initialized the bean of the ConfigurationBeanFactoryMetadata class.

Transform nacos source code

This method is generally caused by the introduction of the following nacos dependencies:

<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 is version 2.4.X and above. After introducing nacos dependency, NoClassDefFoundError error is reported:
image.png

The specific reason is that after the project is started, when the NacosBootConfigurationPropertiesBinder bean is initialized, the bean of the ConfigurationBeanFactoryMetadata class will be fetched from the Spring context:

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

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

Since the spring-boot-2.6.3 version deleted the ConfigurationBeanFactoryMetadata class, a NoClassDefFoundError error will be reported.
The NacosBootConfigurationPropertiesBinder class appears in the nacos-config-spring-boot-autoconfigure dependency package:
image.png
First, you need to download the nacos-spring-boot-project source code:
image.png
Then modify the NacosBootConfigurationPropertiesBinder class. The main purpose of the modification is to replace the ConfigurationBeanFactoryMetadata class and then modify it. version number, then repackage, deploy to maven private server, and then introduce the modified version into the project. For specific modification methods, please refer to: https://blog.csdn.net/demontxy/article/details/122187321

My projects and solutions:

First, the project depends on the version:

<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>

When the project is started, a NoClassDefFoundError error is reported when initializing the configurationPropertiesBeans of ConfigurationPropertiesRebinderAutoConfiguration. The reason mentioned above is that the ConfigurationBeanFactoryMetadata class has been deleted in higher spring versions (2.4.X and above).

@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;
}

First, let’s take a look at the ConfigurationPropertiesRebinderAutoConfiguration class. This class comes from the spring-cloud-context-2.0.4.RELEASE package. The spring-cloud-context package comes from the spring-cloud-starter-alibaba-nacos-config dependency package:
image.png
image.png
spring -cloud-context-2.0.4.RELEASE This package version is relatively low and is adapted to the relatively low spring-boot version. For this reason, it is speculated that the dependence on the ConfigurationBeanFactoryMetadata class will be deleted in the updated spring-cloud-context package (adapted to higher spring-boot versions, such as 2.5.X), because the higher version of the spring-boot package will be deleted If the ConfigurationBeanFactoryMetadata class is installed, the spring-cloud version that is compatible with it will also remove its dependence on this class.

Based on the above ideas, to solve the NoClassDefFoundError error of the ConfigurationBeanFactoryMetadata class,
you can upgrade the versions of spring-cloud-starter-alibaba-nacos-discovery and spring-cloud-starter-alibaba-nacos-config to a higher version, such as:

<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>

This version of the nacos package depends on the relatively high version of spring-cloud-context-3.1.1. In this version, the ConfigurationPropertiesRebinderAutoConfiguration class removes its dependence on the ConfigurationBeanFactoryMetadata class.
image.png

On the other hand, if you don’t want to upgrade the versions of spring-cloud-starter-alibaba-nacos-discovery and spring-cloud-starter-alibaba-nacos-config, you can also directly upgrade the dependency package spring-cloud-context. After all, the NoClassDefFoundError error is Because the dependency package version is too low, you can directly upgrade the spring-cloud-context version to 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>

Guess you like

Origin blog.csdn.net/Princeliu999/article/details/132780850