Spring Boot 2.5.4 应用程序中的 JedisClient 初始化时出现 ClassNotFoundException

ClassNotFoundException while JedisClient initialization in Spring Boot 2.5.4 application

我有一个 Spring Boot 2.5.4 应用程序,我想在其中添加 Redis 并通过 Spring Data Redis 访问它。我当前的配置如下所示:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.4</version>
    <relativePath/>
  </parent>
  <groupId>com.application</groupId>
  <artifactId>ApiGateway</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>ApiGateway</name>
  <description>ApiGateway</description>
  <properties>
    <java.version>15</java.version>
    <spring-boot-starter-redis.version>2.5.0</spring-boot-starter-redis.version>
    <redis.version>3.1.0</redis.version>
  </properties>
  <dependencies>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <version>${spring-boot-starter-redis.version}</version>
    </dependency>

    <!-- OTHER DEPENDENCIES -->
    
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>${redis.version}</version>
      <type>jar</type>
    </dependency>

    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-cognitoidp</artifactId>
      <version>${aws.sdk.version}</version>
    </dependency>

    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk</artifactId>
      <version>${aws.sdk.version}</version>
    </dependency>

    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-core</artifactId>
      <version>${aws.sdk.version}</version>
    </dependency>

    <!-- OTHER DEPENDENCIES -->

  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
            </exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

RedisConfiguration.java

@Configuration
@PropertySource("classpath:redis.properties")
public class RedisConfiguration {

  @Value("${redis.host}")
  private String host;

  @Value("${redis.port}")
  private int port;

  @Value("${redis.database}")
  private int database;

  @Value("${redis.password}")
  private String password;

  @Value("${redis.timeout}")
  private String timeout;

  @Bean
  public JedisConnectionFactory jedisConnectionFactory() {
    RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
    redisConfiguration.setHostName(host);
    redisConfiguration.setPort(port);
    redisConfiguration.setDatabase(database);
    redisConfiguration.setPassword(RedisPassword.of(password));

    JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
    jedisClientConfiguration.connectTimeout(Duration.ofMillis(Long.parseLong(timeout)));

    return new JedisConnectionFactory(redisConfiguration, jedisClientConfiguration.build());
  }

  @Bean
  public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(jedisConnectionFactory());
    return template;
  }
}

我正在接收应用程序启动时的当前配置

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.core.RedisTemplate]: Factory method 'redisTemplate' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jedisConnectionFactory' defined in class path resource [com/application/apigateway/intrastructure/cache/RedisConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.jedis.JedisConnectionFactory]: Factory method 'jedisConnectionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: redis/clients/jedis/DefaultJedisClientConfig
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
    ... 33 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jedisConnectionFactory' defined in class path resource [com/application/apigateway/intrastructure/cache/RedisConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.jedis.JedisConnectionFactory]: Factory method 'jedisConnectionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: redis/clients/jedis/DefaultJedisClientConfig
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean[=13=](AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.resolveBeanReference(ConfigurationClassEnhancer.java:362)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:334)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244.jedisConnectionFactory(<generated>)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration.redisTemplate(RedisConfiguration.java:51)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244.CGLIB$redisTemplate[=13=](<generated>)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244$$FastClassBySpringCGLIB$$c9ce6595.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244.redisTemplate(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 34 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.connection.jedis.JedisConnectionFactory]: Factory method 'jedisConnectionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: redis/clients/jedis/DefaultJedisClientConfig
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
    ... 57 common frames omitted
Caused by: java.lang.NoClassDefFoundError: redis/clients/jedis/DefaultJedisClientConfig
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.<init>(JedisConnectionFactory.java:97)
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.<init>(JedisConnectionFactory.java:232)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration.jedisConnectionFactory(RedisConfiguration.java:45)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244.CGLIB$jedisConnectionFactory(<generated>)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244$$FastClassBySpringCGLIB$$c9ce6595.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.application.apigateway.intrastructure.cache.RedisConfiguration$$EnhancerBySpringCGLIB$c8a244.jedisConnectionFactory(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 58 common frames omitted
Caused by: java.lang.ClassNotFoundException: redis.clients.jedis.DefaultJedisClientConfig
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    ... 71 common frames omitted

到目前为止,我已经尝试通过减少和增加它来操纵 redis.clientsspring-boot-starter-data-redis 版本,但总是会出现初始化问题。我发现的每一个教程都不包含新 Spring 启动应用程序版本的配置。对于如何操作 redis.clientsspring-boot-starter-data-redis 的 pom.xml 版本以使应用程序重新启动的建议,我将不胜感激。

spring-boot-starter-data-redis 已经包含 jedis 作为依赖项,因此您不应该将它添加到您的 pom.xml 中,因为它的版本可能与您的 spring-boot-starter-data-redis 不兼容。

spring-boot-starter-data-redis 版本 2.5.0 的情况下,它包括 jedis 版本 3.6.3 但您用版本 3.1.0 覆盖它,它可能与 spring-boot-starter-data-redis 版本 2.5.0.

始终检查 Spring 引导启动程序中已经包含的依赖项,因为不兼容正是他们试图避免的。

说了这么多,我不完全确定这会解决问题,但这是一个很好的起点。


更新 26/01/2022

spring-boot-starter-data-redis 依赖项 pom.xml 包括以下依赖项:

<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-redis</artifactId>
  <version>2.5.1</version>
  <scope>compile</scope>
</dependency>

spring-data-redis 依赖项 pom.xml 已经包含 jedis 版本:

<properties>
  (...)
  <jedis>3.6.0</jedis>
  (...)
</properties>

以及依赖项本身:

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>${jedis}</version>
  <optional>true</optional>
</dependency>

这意味着您应该只将依赖项添加到您的 pom.xml 但不设置任何版本,以便在 spring-data-redis 中设置的版本如下使用:

<dependencies>
  (...)
  <!-- OTHER DEPENDENCIES -->
  
  <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
  </dependency>
  
  (...)
  <!-- OTHER DEPENDENCIES -->
</dependencies>