获取 A 组件需要一个名为 'redisTemplate' 的 bean,但找不到。用于多个不同的 RedisTemplates 配置

Getting A component required a bean named 'redisTemplate' that could not be found. for multi different RedisTemplates configuration

我在连接同一实例范围内的两个不同 Redis 数据库时遇到问题。我的 Redis 配置 class 如下所示:

package com.application.apigateway.intrastructure.cache;


import java.time.Duration;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

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

  private static final String REDIS_PROPERTIES = "redis.properties";
  private final Properties redisProperties = readConfigurationFile(REDIS_PROPERTIES);

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

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

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

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

  @Bean(name = "redisUserConnectionFactory")
  public JedisConnectionFactory redisUserConnectionFactory() {
    RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
    String userDb = getProperty(redisProperties, "redis.user.cache.database");

    redisConfiguration.setHostName(host);
    redisConfiguration.setPort(port);
    redisConfiguration.setDatabase(Integer.parseInt(userDb));
    redisConfiguration.setPassword(RedisPassword.of(password));

    JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
    jedisClientConfiguration.connectTimeout(Duration.ofMillis(Long.parseLong(timeout)));
    log.info(
        "Connected to Redis host: {}, port: {}, database: {}",
        redisConfiguration.getHostName(),
        redisConfiguration.getPort(),
        redisConfiguration.getDatabase());

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

  @Bean(name = "userRedisTemplate")
  public RedisTemplate<String, Object> userRedisTemplate(
      @Qualifier(value = "redisUserConnectionFactory")
          RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
  }

  @Bean(name = "redisRegistrationTokenConnectionFactory")
  public JedisConnectionFactory redisRegistrationTokenConnectionFactory() {
    RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();

    String registrationTokenDb =
        getProperty(redisProperties, "redis.registration.token.cache.database");
    redisConfiguration.setHostName(host);
    redisConfiguration.setPort(port);
    redisConfiguration.setDatabase(Integer.parseInt(registrationTokenDb));
    redisConfiguration.setPassword(RedisPassword.of(password));

    JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
    jedisClientConfiguration.connectTimeout(Duration.ofMillis(Long.parseLong(timeout)));
    log.info(
        "Connected to Redis host: {}, port: {}, database: {}",
        redisConfiguration.getHostName(),
        redisConfiguration.getPort(),
        redisConfiguration.getDatabase());

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

  @Bean(name = "registrationTokenRedisTemplate")
  public RedisTemplate<String, Object> registrationTokenRedisTemplate(
      @Qualifier(value = "redisRegistrationTokenConnectionFactory")
          RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
  }
}

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>Application - ApiGateway</description>
  <properties>
    <java.version>15</java.version>

    <apache.common.math.version>3.6.1</apache.common.math.version>
    <guava.version>28.1-jre</guava.version>
    <h2.version>1.4.200</h2.version>
    <hamcrest.version>2.1</hamcrest.version>
    <http.client.version>4.5.9</http.client.version>
    <junit.jupiter.version>5.3.2</junit.jupiter.version>
    <junit.surefire.version>1.1.0</junit.surefire.version>
    <lombok.version>1.18.20</lombok.version>
    <mapstruct.version>1.3.0.Final</mapstruct.version>
    <maven.compiler.version>3.8.0</maven.compiler.version>
    <mockito.junit.jupiter.version>2.23.0</mockito.junit.jupiter.version>
    <mysql.driver.version>8.0.18</mysql.driver.version>
    <pdf.box.version>2.0.16</pdf.box.version>
    <postgres.driver.version>42.2.8</postgres.driver.version>
    <spring.security.version>5.2.0.RELEASE</spring.security.version>
    <aws.sdk.version>1.11.870</aws.sdk.version>
    <commons.lang.version>2.6</commons.lang.version>
    <spring.boot.configuration.processor.version>2.2.6.RELEASE
    </spring.boot.configuration.processor.version>
    <json-smart.version>2.3</json-smart.version>
    <spring-cloud.version>2020.0.3</spring-cloud.version>
    <spring-boot-starter-redis.version>2.5.0</spring-boot-starter-redis.version>
    <redis.version>3.7.0</redis.version>
    <spring-cloud-starter-netflix-zuul.version>2.2.9.RELEASE</spring-cloud-starter-netflix-zuul.version>
    <spring-cloud-starter-eureka-client.version>3.0.3</spring-cloud-starter-eureka-client.version>
    <nimbus-jose-jwt>9.11.1</nimbus-jose-jwt>
    <maven-plugin-version>2.5.5</maven-plugin-version>
  </properties>
  <dependencies>

    <!-- SPRING STARTERS -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      <version>${spring-cloud-starter-eureka-client.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.hamcrest</groupId>
          <artifactId>hamcrest-core</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.hamcrest</groupId>
          <artifactId>hamcrest-library</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

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

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

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
      <version>${spring-cloud-starter-netflix-zuul.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

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

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <version>${spring.boot.configuration.processor.version}</version>
    </dependency>


    <!-- SPRING -->
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-core</artifactId>
      <version>${spring.security.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
      <version>${spring.security.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
      <version>${spring.security.version}</version>
    </dependency>

    <!-- OTHERS -->

    <dependency>
      <groupId>com.nimbusds</groupId>
      <artifactId>nimbus-jose-jwt</artifactId>
      <version>${nimbus-jose-jwt}</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-math3</artifactId>
      <version>${apache.common.math.version}</version>
    </dependency>

    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>${commons.lang.version}</version>
    </dependency>

    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>${http.client.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.pdfbox</groupId>
      <artifactId>pdfbox</artifactId>
      <version>${pdf.box.version}</version>
    </dependency>

    <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct-processor</artifactId>
      <version>${mapstruct.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct</artifactId>
      <version>${mapstruct.version}</version>
    </dependency>

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>${guava.version}</version>
    </dependency>

    <dependency>
      <groupId>net.minidev</groupId>
      <artifactId>json-smart</artifactId>
      <version>${json-smart.version}</version>
    </dependency>

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

    <!-- DB -->
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>${h2.version}</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql.driver.version}</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>${postgres.driver.version}</version>
      <scope>runtime</scope>
    </dependency>

    <!-- TEST -->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>${junit.jupiter.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit.jupiter.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>${junit.jupiter.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-library</artifactId>
      <version>${hamcrest.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-core</artifactId>
      <version>${hamcrest.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-junit-jupiter</artifactId>
      <version>${mockito.junit.jupiter.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-test</artifactId>
      <version>${spring.security.version}</version>
      <scope>test</scope>
    </dependency>

  </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>
    <finalName>app</finalName>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${maven-plugin-version}</version>
      </plugin>
    </plugins>
  </build>

</project>

应用程序启动时我收到:

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean named 'redisTemplate' that could not be found.


Action:

Consider defining a bean named 'redisTemplate' in your configuration.

我有点困惑,因为我创建了两个分开的 RestTemplate beans,但它仍然没有带来理想的效果。对于如何解决此问题的建议,我将不胜感激。

我找到了解决办法,即:

  1. 必须将 spring-boot-starter-data-redis 升级到版本 2.5.4
  2. 添加了默认 RedisTemplateJedisConnectionFactory beans

我的 RedisConfiguration class 如下所示:

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

  private static final String REDIS_PROPERTIES = "redis.properties";
  private final Properties redisProperties = readConfigurationFile(REDIS_PROPERTIES);

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

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

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

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

  @Bean(name = "jedisConnectionFactory")
  JedisConnectionFactory jedisConnectionFactory() {
    return new JedisConnectionFactory();
  }

  @Bean(name = "redisTemplate")
  public RedisTemplate<String, Object> redisTemplate(
      @Qualifier(value = "jedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setKeySerializer(stringRedisSerializer());
    template.setValueSerializer(stringRedisSerializer());
    return template;
  }

  @Bean(name = "redisUserConnectionFactory")
  public JedisConnectionFactory redisUserConnectionFactory() {
    RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
    String userDb = getProperty(redisProperties, RedisDb.USER_DB);

    setRedisProperties(redisConfiguration, userDb);

    JedisClientConfiguration jedisClientConfiguration =
        JedisClientConfiguration.builder()
            .connectTimeout(Duration.ofMillis(Long.parseLong(timeout)))
            .build();
    logRedisConnectionDetails(redisConfiguration);

    return new JedisConnectionFactory(redisConfiguration, jedisClientConfiguration);
  }

  @Bean(name = "userRedisTemplate")
  public RedisTemplate<String, Object> userRedisTemplate(
      @Qualifier(value = "redisUserConnectionFactory")
          RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setKeySerializer(stringRedisSerializer());
    template.setValueSerializer(stringRedisSerializer());
    return template;
  }

  @Bean(name = "redisRegistrationTokenConnectionFactory")
  public JedisConnectionFactory redisRegistrationTokenConnectionFactory() {
    RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();

    String registrationTokenDb = getProperty(redisProperties, RedisDb.REGISTRATION_TOKEN_DB);
    setRedisProperties(redisConfiguration, registrationTokenDb);

    JedisClientConfiguration jedisClientConfiguration =
        JedisClientConfiguration.builder()
            .connectTimeout(Duration.ofMillis(Long.parseLong(timeout)))
            .build();
    logRedisConnectionDetails(redisConfiguration);

    return new JedisConnectionFactory(redisConfiguration, jedisClientConfiguration);
  }

  @Bean(name = "registrationTokenRedisTemplate")
  public RedisTemplate<String, Object> registrationTokenRedisTemplate(
      @Qualifier(value = "redisRegistrationTokenConnectionFactory")
          RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setKeySerializer(stringRedisSerializer());
    template.setValueSerializer(stringRedisSerializer());
    return template;
  }

  @Bean(name = "stringRedisSerializer")
  public StringRedisSerializer stringRedisSerializer() {
    return new StringRedisSerializer();
  }

  private void setRedisProperties(RedisStandaloneConfiguration redisConfiguration, String redisDb) {
    redisConfiguration.setHostName(host);
    redisConfiguration.setPort(port);
    redisConfiguration.setDatabase(Integer.parseInt(redisDb));
    redisConfiguration.setPassword(RedisPassword.of(password));
  }

  private void logRedisConnectionDetails(RedisStandaloneConfiguration redisConfiguration) {
    log.info(
        "Connected to Redis host: {}, port: {}, database: {}",
        redisConfiguration.getHostName(),
        redisConfiguration.getPort(),
        redisConfiguration.getDatabase());
  }
}

这种方法解决了一个问题。