6

With Spring Boot 2.1 I am defining a RedisCacheManager bean in a configuration file, with Java configuration. Everything works correctly but I would like sometimes to disable it, for instance in the tests. Spring Boot provides the spring.cache.type=NONE to disable caching, as per this documentation. However, this property will not work because I already define a CacheManager, and as such Spring Boot will not configure the NoOpCacheManager I would like there (there is a @ConditionalOnMissingBean(CacheManager.class) on the NoOpCacheConfiguration which has lower precedence than RedisCacheConfiguration).

When defining caches, whatever the provider (for intance Caffeine), we usually define them as beans, which are afterwards resolved by Spring Boot's auto-configuration into a SimpleCacheManager. For instance

    @Bean
    public Cache myCache() {
        return new CaffeineCache(
                "my-cache",
                Caffeine.newBuilder()
                        .maximumSize(10)
                        .build());
    }

Unfortunately this is not possible with Redis, because its Cache implementation, RedisCache, is not public.

Another thing we like to do is to define a bean CacheManagerCustomizer<?>, for instance with Caffeine

    @Bean
    public CacheManagerCustomizer<CaffeineCacheManager> caffeineCacheManager() {
        return cacheManager -> cacheManager
                .setCaffeine(Caffeine.newBuilder()
                        .expireAfterWrite(1, TimeUnit.MINUTES));
    }

Again this is not possible with Redis, as RedisCacheManager is immutable.

So the only solution right now is to create our own RedisCacheManager, but this prevent the usage of spring.cache.type: NONE.

So here is my question. What is the best way to configure a Redis cache with Spring Boot so that we can disable it as needed ?

Lukas Cardot
  • 166
  • 1
  • 2
  • 12

2 Answers2

12

I had a requirement to enable/disable Redis auto configuration from spring.cache.type property. The below code solved my issue. This might help for anyone who want to disable/enable redis just by changing single property, in my case it is spring.cache.type=redis. Below are the major configurations.

@SpringBootApplication(exclude = {RedisAutoConfiguration.class})
public class SpringBootApp extends SpringBootServletInitializer {

}
@ConditionalOnProperty(prefix = "spring", name = "cache.type", havingValue = "redis")
@Configuration
@Import({ RedisAutoConfiguration.class })
public class ApplicationRedisConfig {

}

To enable auto configuration from application.yaml

spring:
  cache:
    type: redis
  redis.host: redis

Health check gives below response when redis is not available which shows that auto configuration has been included.

{
  "status": "DOWN",
  "details": {
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 486730272768,
        "free": 216405499904,
        "threshold": 10485760
      }
    },
    "db": {
      "status": "UP",
      "details": {
        "database": "PostgreSQL",
        "hello": 1
      }
    },
    "elasticsearch": {
      "status": "UP"
    },
    "redis": {
      "status": "DOWN",
      "details": {
        "error": "org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to redis:6379"
      }
    }
  }
}

To disable auto configuration from application.yaml

spring:
  cache:
    type: simple
  redis.host: redis

Health check gives below response which shows redis has been excluded from auto configuration.

{
  "status": "UP",
  "details": {
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 486730272768,
        "free": 215928782848,
        "threshold": 10485760
      }
    },
    "db": {
      "status": "UP",
      "details": {
        "database": "PostgreSQL",
        "hello": 1
      }
    },
    "elasticsearch": {
      "status": "UP"
    }
  }
}
Rahogata
  • 426
  • 6
  • 15
0

exclude attribute of the @SpringBootApplication annotation, something like: @SpringBootApplication( exclude = { RedisAutoConfiguration.class } )

and set: spring.data.redis.repositories.enabled=false

Vishnu Atrai
  • 2,370
  • 22
  • 24
  • 5
    I would prefer not to rely on configuration exclusion, since it might break parts of our application. For instance if we want to inject the `RedisCacheManager` somewhere (for whatever reason), the application would fail. `spring.cache.type: NONE` let us do that – Lukas Cardot May 09 '19 at 11:58
  • 2
    Yes, thanks. So finally, I added 3 properties to make it work: `spring.cache.type: simple, spring.data.redis.repositories.enabled: false, spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration`. Also I added a `CacheManager` bean to test config to let the cache be configured (as well as adding `@ConditionalOnProperty(name = "redis.host")` to the production config) – Frankie Drake Sep 23 '19 at 07:28