In Spring Boot, I would like to use one cache manager defined as bean plus Redis cache defined in application.yaml. But after define cache manager like bean the other one in application.yaml is ignored.
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager(LDAP_CACHE_NAME) {
@Override
protected Cache createConcurrentMapCache(final String name) {
return new ConcurrentMapCache(name, CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).maximumSize(100).build().asMap(), false);
}
};
}
application.yaml:
spring:
redis:
host: localhost
cache:
type: redis
cache-names: REDISCACHE
cache-specs:
myCustomCache:
time-to-live: 600s
2
Answers
With Spring Boot, you do NOT need to explicitly define/declare a
CacheManager
bean.For example, when both the
spring-boot-starter-cache
(here) andspring-boot-starter-data-redis
(here) dependencies are declared on your Spring Boot application classpath, then Spring Boot will auto-configure aCacheManager
bean for you. Also, check out this link fromstart.spring.io
, which will get you started.You still need to enable caching, by declaring the Spring cache
@EnableCaching
annotation on 1 of your Spring application@Configuration
classes (see docs), but you do NOT need to explicitly declare aCacheManager
bean. Doing so will actually override the auto-configuration in Spring Boot even, and in your case, that is this Spring Boot auto-configuration class (source) in particular (for Redis). See the RedisCacheManager
bean here provided for you by Spring Boot.So, what you have effectively done by declaring an explicit
CacheManager
bean (theConcurrentMapCacheManager
bean, no less), is override Spring Boot’s auto-configuration (for instance, this). That is, Spring Boot will only auto-configure a RedisCacheManager
bean if you have not explicitly done so yourself.This is what it means when Spring Boot says, "convention over configuration" unless you explicitly specify yourself, then Spring Boot quietly backs away and assumes you know what you are doing (See more details, here).
To make matters worse, you declared a
ConcurrentMapCacheManager
bean, which will not use or store anything in Redis, as a caching provider. It will simply use a in-memory,ConcurrentMap
(ajava.util.concurrent.ConcurrentHashMap
to be precise) to cache results from your Spring Boot application service methods, resulting in bypassing Redis altogether.So, you inadvertently shot yourself in the foot, 😉
Hope this helps!
From Grampa’s Trick Box
The trick is:
@Bean CacheManager
(tricking@ConditionalOnMissingBean(CacheManager.class)
/leaving auto configuration)redisCache
is rather optional in this example, key point: "wrap your (autoconfigured + custom) bean"Then you can access the custom cache manager from spring context:
#{@myAwesomeCMWrapper.localCache}
(SpEL)@Autowried MyAwesomeCMWrapper ... getLocalCache()
(java config)