Search code examples
javaspringspring-bootredisspring-data-redis

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


I am facing a problem with connecting to two different Redis databases in the scope of the same instance. My Redis configuration class looks like this:

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

and

pom.xml looks like:

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

While the application starts I am receiving:

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

I am a little bit confused because I created two separated RestTemplate beans and it still doesn't bring a desirable effect. I will be grateful for suggestions on how to fix this problem.


Solution

  • I have found a solution, namely:

    1. had to upgrade spring-boot-starter-data-redis to version 2.5.4
    2. added default RedisTemplate and JedisConnectionFactory beans

    My RedisConfiguration class looks like below:

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

    This approach resolved a problem.