I want to have multiple spring cache managers configured in my web-application and I would be able to use different cache manager at various places in my project. Is there any way to do this.
A new cache based on the default configuration can be added to a CacheManager very simply: manager. addCache(cacheName);
Spring provides two ways to evict a cache, either by using the @CacheEvict annotation on a method, or by auto-wiring the CacheManger and clearing it by calling the clear() method.
Interface CacheManagerAllows for retrieving named Cache regions.
There are several ways you can do this and the right answer depends on your usage of the cache.
If you use CacheManager A for 90% of your use case and B for 10% I'd advise to create a default CacheManager
for A (you'll need to specify it via a CacheConfigurerSupport
extension), something like:
@Configuration @EnableCaching public class CacheConfig extends CachingConfigurerSupport { @Override @Bean // not strictly necessary public CacheManager cacheManager() { ... CacheManager A } @Bean public CacheManager bCacheManager() { ... CacheManager B } }
Then for the 10% use case you add a CacheConfig
at the top of the classes that need to use the other cache manager
@CacheConfig(cacheManager="bCacheManager") public class MyService { /*...*/ }
If you need to use the other cache manager for only one method, you can specify that at method level as well
@Cacheable(cacheNames = "books", cacheManager = "bCacheManager") public Book findById(long id) { /*...*/ }
If you're not in this situation, you need a way to know which cache manager needs to be used on a case-by-case basis. You can do that based on the target type (MyService
) or the name of the cache (books
). You'll need to implement a CacheResolver
that does that translation for you.
@Configuration @EnableCaching public class CacheConfig extends CachingConfigurerSupport { @Override public CacheResolver cacheResolver() { ... } }
Check the javadoc of CacheResolver
for more details. In the implementation, you may have several CacheManager
instances (either as bean or not) that you'll call internally based on your logic to determine which manager should be used.
I saw in a comment that you were referring to "module". Caching is really an infrastructure matter so I'd strongly advice you to move that decision at the application level. You may tag cache as being "local" and others being "clustered". But you should probably have some kind of nomenclature for the name to make it easier. Don't choose a cache manager at the module level.
this blog post illustrates this with other examples.
As @Stephane Nicoll explained, you have several options. I will try to give some info on custom CacheResolver
. CacheResolver
has one method:
Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);
which gives context to the cacheable operation's class, method, arguments etc.
In its basic form:
public class CustomCacheResolver implements CacheResolver { private final CacheManager cacheManager; public CustomCacheResolver(CacheManager cacheManager){ this.cacheManager = cacheManager; } @Override public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) { Collection<Cache> caches = getCaches(cacheManager, context); return caches; } private Collection<Cache> getCaches(CacheManager cacheManager, CacheOperationInvocationContext<?> context) { return context.getOperation().getCacheNames().stream() .map(cacheName -> cacheManager.getCache(cacheName)) .filter(cache -> cache != null) .collect(Collectors.toList()); } }
Here I am using one CacheManager
for brevity. But you can bind different CacheManager
s to CacheResolver
and make more granular selections: if class name is X
, then use GuavaCacheManager
, otherwise use EhCacheCacheManager
.
After this step, you should register CacheResolver
, (again you can bind more CacheManagers
here):
@Configuration @EnableCaching public class CacheConfiguration extends CachingConfigurerSupport { @Bean @Override public CacheManager cacheManager() { // Desired CacheManager } @Bean @Override public CacheResolver cacheResolver() { return new CustomCacheResolver(cacheManager()); } }
And as the last step, you should specify CustomCacheResolver
in one of @Cacheable
, @CachePut
, @CacheConfig
etc. annotations.
@Cacheable(cacheResolver="cacheResolver")
You can look here for code samples.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With