Issue
I have a requirement to invoke some functionality when @CacheEvict is being called. Is there a way to call a listener or interceptor to be invoked in Spring @CacheEvict?
Solution
Typically, this is very "cache provider" specific since no 2 cache providers have the same capabilities.
For instance, I primarily work with In-Memory Data Grid (IMDG) technology like Pivotal GemFire and the OSS version Apache Geode. Both, of which, can be used as a "caching provider" in Spring's Cache Abstraction. With GemFire/Geode, you can register a o.a.g.cache.CacheListener
callback on the GemFire/Geode Region
(essentially a java.util.Map
) that is backing the Spring Cache
interface, and used in Spring's Caching infrastructure as the "Adapter" to the backing store. As you can see with SD GemFire/Geode provider implementation, the "eviction" triggers a GemFire/Geode Region.remove(key)
. This eviction can subsequently be captures and handled in the Region's
registered CacheListener.afterDestroy(:EntryEvent) callback method.
However, this is just 1 way to handle notifications on evictions in your application.
Of course, as @Borino pointed out, you can leverage Spring's AOP support to "intercept" the cache eviction operation. The advantage of this approach is that it is more generic and reusable across different caching providers.
Although, I would say that you should not be developing a AOP Pointcut expression based on the underlying "caching provider", as @Borino instructed, i.e. ...
execution(* org.springframework.cache.concurrent.ConcurrentMapCache.evict(..))
This expression ties your AOP Aspect to the ConcurrentMapCache
"provider", the default in Spring's Cache Abstraction (and in Spring Boot).
What happens when you use Ehcache, Hazelcast, Redis, GemFire/Geode or multiple combinations of these "providers" in your application?
Rather, you can slightly adjust the AOP Pointcut expression to this...
execution(* org.springframework.cache.Cache.evict(..))
See here. This is safe because all "caching providers" must supply 2 things: a CacheManager
implementation and a Cache
implementation for each cache specified in the application. Again, the Cache
interface is a "Adapter" to the backing store. Again, see the docs for more details.
There are tradeoffs with either approach. Provider specific solutions generally give your more control capabilities, but using the AOP approach is more reusable. Do what is right for your UC.
Hope this helps.
Cheers! -John
Answered By - John Blum