In the previous article, we has understood about How Spring Caching works. So in this article, we will discuss about annotations in Spring caching, and how to use it in our source code.
Table of contents
Introduction to Cache
In computing, a cache is a component that transparently stores data so that future requests for that data can be served faster. The data that is stored within a cache might be values that have been computed earlier or duplicates of original values that are stored elsewhere.
If requested data is contained in the cache (cache hit), this request can be served by simply reading the cache, which is comparatively faster.
Otherwise (cache miss), the data has to be recomputed or fetched from its original storage location, which is comparatively slower.
Hence, the greater the number of requests that can be served from the cache, the faster the overall system performance becomes.
Annotations in Spring Caching
-
@EnableCaching
annotation@Configuration @EnableCaching public class AppConfig { // EhCache Manager @Bean public CacheManager cacheManager() { //A EhCache based Cache manager return new EhCacheCacheManager(ehCacheCacheManager().getObject()); } //JDK Cache Manager @Primary @Bean public CacheManager jdkCacheManager() { return new ConcurrentMapCacheManager("users"); } // JSR 107 - JCache Manager @Bean public CacheManager jCacheManager() { return new JCacheCacheManager(); } //Guava Cache Manager @Bean public CacheManager guavaCacheManager() { return new GuavaCacheManager(); } @Bean public EhCacheManagerFactoryBean ehCacheCacheManager() { EhCacheManagerFactoryBean factory = new EhCacheManagerFactoryBean(); factory.setConfigLocation(new ClassPathResource("ehcache.xml")); factory.setShared(true); return factory; } }
The
@EnableCaching
annotation, usually applied on a@Configuration
class, triggers a post processor that inspects everySpring bean
for the presence of caching annotations on public methods. If such an annotation is found, aproxy
is automatically created to intercept the method call and handle the caching behavior accordingly.The annotations that are managed by this post processor are
@Cacheable
,@CachePut
and@CacheEvict
.Spring Boot automatically configures a suitable
org.springframework.cache.CacheManager
to serve as a provider for the relevant cache.org.springframework.cache.CacheManager
is the common Cache abstraction provided by Spring to handle all caching related activities.CacheManager
controls and managesorg.springframework.cache.Cache
s and can be used to retrieve these for storage. Since it’s an abstraction, we need a concrete implementation for cache store. Several options are available in market: JDKjava.util.concurrent.ConcurrentMap
based caches,EhCache
,Gemfire cache
,Caffeine
,Guava caches
andJSR-107 caches
.This annotation supplies 3 parrameters:
mode
: indicates how caching advice should be applied.order
: specifies the ordering of the execution of the caching advisor when multiple advices are applied at a specific joinpoint.proxyTargetClass
: indicates whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies.
-
@Cacheable
annotationThis annotation will define a cache for a method’s return value.
When our application is received multiple requests, then this annotation will not execute the method multiple times, instead it will send the result from the cached storage.
@Cacheable(value = "user-cache", key="#userSearchVO.name", condition="#supportUser == false") public User findUser(UserSearchVO userSearchVO, boolean supportUser) { User foundUser = null; ... ... ... return foundUser; }
In the above example, we have;
value = "user-cache"
indicates the name of the cache in which entries are stored.key="#searchVO.name"
defines the key to lookup into the cache. Here it is the name property of the UserSearchVO object condition=”#supportUser == false” provides the condition to trigger the cache. The cache lookup and the method result caching are triggered only when the supportUser flag is set to false
@Cacheable
annotation includes some properties that is listed in the below table.Attributes Description cacheManager The bean name of the cache manager cacheNames The list of cache store names where the method cache has to be stored. This should be any array of strings. cacheResolver The name of the custom cache resolver. condition This is Spring Expression Language (SPeL) for the conditional caching for the method. key Spring Expression Language for computing the key dynamically. keyGenerator The bean name of the custom key generator to use. unless SPeL for bypassing caching for specific scenarios. value It is a cache name to store the caches, and it is mandatory For example:
// Use key: id of location @Cacheable(value = "concerts", key = "#location.id", cacheManager = "gemfireCacheManager") public List<Concert> findConcerts(Location location) { ... } // key: hashCode of location @Cacheable(value = "concerts", key = "T(someType).hash(#location)", cacheResolver = "myOwnCacheResolver") public List<Concert> findConcerts(Location location) { ... } // conditional caching if location is in Dallas in operating. @Cacheable(value = "concerts", condition = "#location.city == 'Dallas'", unless = "#location.outOfBusiness") public List<Concert> findConcerts(Location location) { ... } // key: generated id of result @Cacheable(value = "concerts", key = "#result.id") public Location saveLocation(Location location) { ... }
Belows is how to custom some properties in
@Cacheable
annotation as same as other annotations.-
Create custom
CacheResolver
.In the above, we have used
myOwnCacheResolver
. Then we will create this custom class with the following code.public class MyOwnCacheResolver extends AbstractCacheResolver { @Autowired public MyOwnCacheResolver(CacheManager cacheManager) { super(cacheManager); } protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) { return getCacheNames(context.getTarget().getClass()); } private getCacheNames(Class<?> businessServiceClass) { ... } }
-
Create custom
KeyGenerator
public class MyOwnKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { if (params.length == 0) { return new SimpleKey("EMPTY"); } if (params.length == 1) { Object param = params[0]; if (param != null && !param.getClass().isArray()) { return param; } } return new SimpleKey(params); } }
-
@CachePut
annotationThis annotation is used to update the cache with the latest execution without stopping the method execution.
The only difference between
@Cacheable
and@CachePut
is that:- With
@Cacheable
, the method will be executed only once and the result will be updated in cache. Subsequent calls to our method will not execute our method, it will just get the result from the cache. - With
@CachePut
, the method is executed every time and the result will be updated to the cache storage.
It is not recommended to use both the annotation for the same method which will result in an unexpected results. It is highly recommended to use either
@Cacheable
or@CachePut
for a method.The list of attributes defined in this annotation is similar to the
@Cacheable
. - With
-
@CacheEvict
annotationThis annotation is used for removing a single cache or clearing the entire cache from the cache storage.
This annotation supports suitable parameters to execute the condition to clear the matching set of cached from the store. If you set the
allEntries=true
, then the entire cache will be cleared.The below is a table includes some properties for this annotation:
Attributes Description allEntries It indicated whether all the data in the cache has to be removed. beforeInvocation This attribute indicates whether the eviction has to be done before the method invocation. cacheManager The bean name ò the cache manager cacheNames The list of cache store names where the method cache has to be stored. This should be any array of strings. cacheResolver The name of the custom cache resolver. condition This is Spring Expression Language (SPeL) for the conditional caching for the method. key Spring Expression Language for computing the key dynamically. keyGenerator The bean name of the custom key generator to use. unless SPeL for bypassing caching for specific scenarios. value It is a cache name to store the caches -
@Caching
annotationIt is used for grouping multiple annotations of the same type together when one annotaion is not sufficient for the specifying the suitable condition.
The properties in this annotations are:
Attributes Description cacheable This is array of @Cacheable
annotationevict This is array of @CacheEvict
annotationput This is array of @CachePut
annotation -
@CacheConfig
annotationIf you have multiple operations in a class where each operation has to be given cache configuration details, this could be tedious job if the number of operations are higher.
We can annotate
@CacheConfig
at the class level to avoid repeated mentioning in each method.For example, in the class level you can provide the cache name and in the method you just annotate with
@Cacheable
annotation.Some properties that are supported in
@CacheConfig
annotation.Attributes Description cacheManager The bean name ò the cache manager cacheNames The list of cache store names where the method cache has to be stored. This should be any array of strings. cacheResolver The name of the custom cache resolver. keyGenerator The bean name of the custom key generator to use.
JCache(JSR - 107)
Since Spring framework 4.1, Spring’s caching abstraction completely supports the JCache specification and we can use JCache annotations without any special configurations.
All annotations in Jcache is used in packge org.springframework.cache.jcache
. We can use Java based configuration by adding some code in our configuration class.
@Bean
public CacheManager jCacheManager() {
return new JCacheCahceManager();
}
Below is the table to discribe about some properties in JCache.
Spring | JCache | Description |
---|---|---|
@Cacheable |
@CacheResult |
Similar, but @CacheResult can cache Exceptions and force method execution. |
@CacheEvict |
@CacheRemove |
Simillar, but @CacheRemove supports in the case of Exceptions. |
@CacheEvict(allEntries=true) |
@CacheRemoveAll |
JCache adds another annotation for removign all the cache entries. |
@CachePut |
@CachePut |
Different semantic: cache content must be annotated with @CacheValue . JCache brings Exception caching and caching before or after method execution. |
@CacheConfig |
@CachePut |
Wrapping up
- We need to find some ways to notify for
CacheManager
updating when we put new data into database. - We do not use Caching overtimes because memory is limited.
Thanks for your reading.
Refer:
https://dzone.com/articles/spring-31-caching-and-0
https://doanduyhai.wordpress.com/2012/07/01/cache-abstraction-in-spring-3/
https://javabeat.net/enablecaching-spring/
https://javabeat.net/spring-cache/