This article introduces the custom cache resolver in spring, by customizing the resolver, you can add additional processing in spring’s cache annotation.
Specific code reference example project
1. Overview
The cache-aside pattern is a commonly used cache usage pattern. The usage flow is as follows.
When the data in the database is updated, the cache is invalidated so that the latest data in the database can be read subsequently, making the cached data consistent with the database data.
In spring, cache processing is done through cache annotations, and cache processing is generally encapsulated in the dao layer so that the business layer does not need to be aware of the details of cache operations and can focus on the business logic.
2. the cache read and invalidate
dao layer operations usually use springdatajpa, database methods are an interface, by adding the corresponding cache annotation to the interface to achieve cache processing.
Read data.
With the Cacheable annotation, data read from the database is written to the cache synchronously.
Saving data.
With the CacheEvict annotation, the cache is invalidated after the data is written to the database. What if we want to perform other operations after cache invalidation, such as writing the key of the invalidated cache to kafka for synchronous deletion of the cache by other systems?
3. Custom Cache Resolver
spring provides a way to customize the cache resolver. By customizing the resolver, you can add additional operations to the cache processing.
|
|
The above code is the configuration of the redis cache, where the RedisCacheManager
part is the configuration of the regular cacheManager, and the customCacheResolver
part is the configuration of the custom resolver. By defining the customCacheResolver
bean, the custom resolver can be referenced in the cache annotation.
After defining the bean of customCacheResolver, we can refer to it in the cache annotation, and the code of the above mentioned data saving method is modified as follows
Compared to the previous implementation, add the specified cacheResolver to CacheEvict.
4. Implementation of custom resolver
Above we have described how to configure and reference the cacheResolver, the following describes the implementation of the custom cacheResolver.
|
|
The above code defines CustomCacheResolver
, a custom resolver class that inherits from SimpleCacheResolver
. The SimpleCacheResolver
class is the default resolver used by spring in the cache annotation. We add additional operations by extending the SimpleCacheResolver
class. Where resolveCaches
is the part that resolves the cache operations. In this part of the code, all we need is to get the value of the key of the cache that is invalidated in the @CacheEvict(value = "testCache", cacheResolver = "customCacheResolver", key = "#p0.id")
annotation. The definition of the key can be read from the parameter context by context.getOperation()).getKey()
, i.e. #p0.id
, which is a spel expression, unlike a normal spel expression, the variable p0 is a variable specific to the jpa method, indicating the first parameter in the method p0 is a variable unique to the jpa method and represents the first argument in the method, while p1 represents the second argument in the method. This spel expression cannot be parsed through normal spel processing. spring provides the MethodBasedEvaluationContext
class for parsing such special spel expressions.
With the following four lines of code, we will be able to get the value of the specific key.
|
|
After getting the value of the key, we can do a lot of operations on this key, we can write this key to kafka and notify other systems to clean up the key synchronously.
5. Summary
When using springdatajpa as a dao layer implementation, the specific dao methods are interfaces, and there is no way to add additional operations to the cache annotations added to the interfaces. When additional processing of cache operations is required, this can be achieved by customizing the resolver and using our custom resolver in the cache annotation. This is a better way to achieve this without breaking the finishing logic of the program, but also extends the operation of the cache.