I’m setting the configuration of a Spring Data Redis Cache on application.properties using the spring.cache.redis.* keys.
However, not everything is possible to be configured on application.properties and I’d like to get a reference to the RedisCacheConfiguration created by Spring and do some further configuration on it.
From all the examples I found, it seems that this is not possible, since all of them show something like:
@Bean
RedisCacheConfiguration getRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
}
And the defaultCacheConfig method just ignores application.properties.
I also tried to get an autowired reference using:
@Bean
public RedisCacheManager getRedisCacheManager(RedisConnectionFactory connectionFactory, RedisCacheConfiguration redisCacheConfiguration) {
...
But that just results in an Exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.cache.RedisCacheConfiguration' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
So, is what I want to do impossible? Should I just forget about application.properties and configure everything in code?
I’m using Spring Boot (with spring-boot-starter-cache and spring-boot-starter-data-redis) 2.7.8, Java 17 and Lettuce 6.1.10.RELEASE.
2
Answers
For reference, I'm posting the solution I ended up with, but John Blum's answer offers more options.
Out of curiosity, what aspect of (Redis) cache configuration are you trying to modify (or customize)?
Reviewing the
RedisCacheConfiguration
class provided by Spring Data Redis (and used by Spring Boot), most of the configuration (allownull
values, key prefix, statistics, TTL) are all configurable using Spring Boot properties. Of course, the properties do not cover non-scalar/primitive type configuration, such as the key/value Redis Serializer pairs or theConversionService
used.First, have a look at this in the Spring Boot reference documentation.
Declaring a
RedisCacheManagerBuilderCustomizer
bean in your application configuration enables you to set (and modify) theRedisCacheConfiguration
for eachRedisCache
instance. This approach gives you complete control over individual cache configuration for each cache separately. See below.Of course, if you declared many different caches for different purposes across your application, then this could be tedious. In addition, if you have predetermined caches declared with the
spring.cache.cache-names
Spring Boot property, which might vary by environment if you are using Spring Profiledapplication.properties
files, then this could also be problematic.On the other hand, even when using a large number of individual caches for different purposes, if they share common configuration then your job becomes much easier.
For shared, common cache configuration, you were on the right track by declaring a bean of type
RedisCacheConfiguration
. Bean name should not matter, though I might prefer "redisCacheConfiguration" rather than "getRedisCacheConfiguration". You can even inject the Spring BootCacheProperties
instance, which Spring Boot does register as a bean in the SpringApplicationContext
.For example:
The (Redis)
CacheProperties
are the resolved properties from Spring Bootapplication.properties
file(s), specific to caching (i.e.spring.cache.*
).This is not unlike what Spring Boot’s auto-configuration already does (follow from here, then here and finally, here) if you do not explicitly declare a bean of type
RedisCacheConfiguration
.The default
RedisCacheConfiguration
provided by Spring Boot is used if you did NOT explicitly declare a bean of typeRedisCacheConfiguration
.You will also notice that Spring Boot does not register the default, provided
RedisCacheConfiguration
as a bean in the SpringApplicationContext
anywhere in the Spring BootRedisCacheConfiguration
class (used in auto-configuration), which is why you encountered aNoSuchBeanDefinitionException
when you tried to inject what you thought was a bean when Spring Boot created the SD RedisRedisCacheConfiguration
object (it doesn’t).Now, how to handle the individual Redis cache configuration when you need to deviate from the (default), shared
RedisCacheConfiguration
that might be applicable to most of your cache instances, but not all of them (perhaps)?This is where the
RedisCacheManagerBuilderCustomizer
can help!Again, as the documentation reference that I shared with you above describes, you must declare a bean of type
RedisCacheManagerBuilderCustomizer
in your application configuration.For example:
The
RedisCacheManagerBuilder
even allows you to specify a defaultRedisCacheConfiguration
to use for all caches if you are not explicitly customizing all individual cache instances. ThecacheDefaults(:RedisCacheConfiguration
) method onRedisCacheManagerBuilder
used to set defaults for all created cache instances alleviates the need for you to declare the customRedisCacheConfiguration
bean explicitly as I demonstrated first, above.Alright, I will leave you with this.
Hopefully it gives you ideas and choices on how to best proceed in your particular case. Just know that Spring always has you covered. It might take a little digging, but I have yet to come across a situation that is not possible.
Good luck!