At its core, the abstraction applies caching to Java methods, reducing thus the numberof executions based on the information available in the cache. That is, each time atargeted method is invoked, the abstraction will apply a caching behavior checkingwhether the method has been already executed for the given arguments. If it has, thenthe cached result is returned without having to execute the actual method; if it hasnot, then method is executed, the result cached and returned to the user so that, thenext time the method is invoked, the cached result is returned. This way, expensivemethods (whether CPU or IO bound) can be executed only once for a given set ofparameters and the result reused without having to actually execute the method again.The caching logic is applied transparently without any interference to the invoker.
Important |
---|
Obviously this approach works only for methods that are guaranteed to return the sameoutput (result) for a given input (or arguments) no matter how many times it is beingexecuted. |
In this quick tutorial, we’re going to illustrate how to create a custom key generator with Spring Cache. For an introduction to the above module, please refer to this article. This is responsible for generating every key for each data item in the cache, which would be used to. @CacheEvict(value = 'user', key = '#id') public void deleteUser(Long id) Implementing a Custom Key Generator. For basic purposes, the default key generation system for cached data works. The parameters to your method become the key in your cache store.
Other cache-related operations are provided by the abstraction such as the abilityto update the content of the cache or remove one of all entries. These are useful ifthe cache deals with data that can change during the course of the application.
Just like other services in the Spring Framework, the caching service is anabstraction (not a cache implementation) and requires the use of an actual storage tostore the cache data - that is, the abstraction frees the developer from having to writethe caching logic but does not provide the actual stores. This abstraction ismaterialized by the
org.springframework.cache.Cache
andorg.springframework.cache.CacheManager
interfaces.There are a few implementations of that abstractionavailable out of the box: JDK
java.util.concurrent.ConcurrentMap
based caches,EhCache, Gemfire cache,Guava caches andJSR-107 compliant caches. See Section 29.7, “Plugging-in different back-end caches” for more information on plugging inother cache stores/providers.Important |
---|
The caching abstraction has no special handling of multi-threaded and multi-processenvironments as such features are handled by the cache implementation. . |
If you have a multi-process environment (i.e. an application deployed on several nodes),you will need to configure your cache provider accordingly. Depending on your use cases,a copy of the same data on several nodes may be enough but if you change the data duringthe course of the application, you may need to enable other propagation mechanisms.
Caching a particular item is a direct equivalent of the typical get-if-not-found-then-proceed-and-put-eventually code blocks found with programmatic cache interaction: no locksare applied and several threads may try to load the same item concurrently. The same appliesto eviction: if several threads are trying to update or evict data concurrently, you mayuse stale data. Certain cache providers offer advanced features in that area, refer tothe documentation of the cache provider that you are using for more details.
To use the cache abstraction, the developer needs to take care of two aspects:
- caching declaration - identify the methods that need to be cached and their policy
- cache configuration - the backing cache where the data is stored and read from
Important Cache Annotations
Spring Framework uses several annotations to manage your caches in an easy way in your application. The important ones are:
- @Cacheable
- @CacheEvict
- @CachePut
- @Caching
@Cacheable
You can place the @Cacheable annotation on a method, on an interface, or a public method on a class. However, as explained earlier, the mere presence of the @Cacheable annotation is not enough to activate the caching behavior in your Spring application. The @Cacheable annotation is simply a metadata that can be consumed by some runtime infrastructure that is @Cacheable-aware and that can use the metadata to configure the appropriate beans with caching behavior. As discussed in earlier section of this same chapter, the element in the Spring XML configuration switches on the caching behavior.
Spring recommends that you only annotate methods of concrete classes with the @Cacheable annotation, as opposed to annotating methods of interfaces. You do have a provision to put @Cacheable annotation on an interface or an interface method, but this will only work if you are using interface-based proxies.
Moreover, when using proxies, you should apply the @Cacheable annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Cacheable annotation, no error is raised, but the annotated method does not exhibit the configured cacheable settings.
Another notable thing is that, only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual cache interception at runtime even if the invoked method is marked with @Cacheable.
@Cacheable Settings
The @Cacheable annotation is a metadata that specifies that a method must have cache semantics. The various properties of the @Cacheable annotation are summarized as shown in Table 10-1 below.
Table 10-1. @Cacheable settings (Attributes which can be used to control caching)
Element Name | Element Type | Description |
value | String[] | Name(s) of the caches in which update needs to take place. It can be used for specifying target cache(s), matching the qualifier value (or the bean name(s)) of (a) specific bean definition. Mandatory element. |
key | String | Spring Expression Language (SpEL) attribute, which can compute keys dynamically. The default value is “” and takes in all the method parameter names as keys. |
condition | String | Spring Expression Language (SpEL) attribute, which can be used for conditioning the method cache. The default value is “”, which means that the method will always be cached. |
Complete example class using the major cache annotation provided by Spring framework is shown in the Listing 10-14. In this section I have used some code snippets for explaining the various elements in the cacheable annotation.
Listing 10-5. A simple usage of @Cacheable annotation
[java]public class CustomerRepository{
@Cacheable(“customer”)
public Customer getCustomer(String customerCode){
//….
}
}[/java]
In Listing 10-5, @Cacheable usage causes method argument to be used as the default keys in storing the method results in the cache. The method “getCustomer” is associated with the cache name “customer”. Each time this method is called, the cache is checked to see if the method has been executed earlier with the same attributes. If so, it returns from cache rather than going to the database. In most cases it is sufficient to declare only one cache but the annotation allows putting multiple cache names, as shown in Listing 10-6, which will then be used to store the cache’s key-value pairs.
Listing 10-6. Usage of @Cacheable annotation with mutiple cache names
[java]public class CustomerRepository{
@Cacheable(“customer”,”generic”)
public Customer getCustomer(String customerCode){
//….
}
}[/java]
In Listing 10-7, “condition” attribute in @Cacheable is used to check if the “customerCode” length is exactly equal to 30. If it satisfies the condition, the caching will be done. You can also calculate appropriate caching conditions on fly.
Listing 10-7. Usage of @Cacheable in which cache conditions are defined
[java]public class CustomerRepository{
@Cacheable(value=“customer”,condition=”#customerCode.length = 30”)
public Customer getCustomer(String customerCode){
//….
}
}[/java]
Listing 10-8, shows calculation the caching condition in which it is only cached if the day in which the method is called is not a weekend (on weekends, the load is less and performance might not be a concern).
Listing 10-8. Usage of @Cacheable in which the cache condition is calculated on the fly
[java]public class CustomerRepository{
@Cacheable(value=“customer”,condition=”!T(TimeUtils).isWeekend()”)
public Customer getCustomer(String customerCode){
//….
}
}[/java]
You have seen in the above sections, how @Cacheable annotation can be used to integrate cache easily into your application. But, we haven’t seen how this annotation helps us in doing thing in a easy manner. Listing 10-9 shows @Cacheable equivalence, that means, it shows what this annotation does it for you.
Listing 10-9. @Cacheable equivalance Java code
[java]import org.springframework.cache.Cache.ValueWrapper;
public class CustomerRepository{
@Inject
CacheManager cacheManager;//Use standard Java annotation @Inject for injection
public Customer getCustomer(String customerCode){
Cache cache = cacheManager.getCache(“customer”);
ValueWrapper mapValue = cache.get(customerCode);
if(mapValue != null){
return (Customer)mapValue.get();
}
//Do appropriate things to get the required customer
Customer customer = //get customer by whatever means
//…..
cache.put(customerCode, customer);
return customer;
}
}[/java]
Key Generation
Caches are essentially key-value stores and each invocation is translated into a suitable key value to access the cache. Spring uses simple key generation methodology using the following algorithm to generate the key for cache invocation:
- If no method parameters are there, the key generator returns 0.
- If only one parameter is present in the method, the key generator returns that instance.
- If more the one parameter is present in the method, the key generator return a key computed from the hashes of all parameters.
Listing 10-10. Explicit way of defining keys for the caching using SpEL – Sample 1
[java]public class CustomerRepository{
@Cacheable(value=“customer”,key=”#customer.customerCode”)
public Customer getCustomer(Customer customer){
//….
}
}[/java]
Listing 10-11. Explicit way of defining keys for the caching using SpEL – Sample 2
[java]public class CustomerRepository{
@Cacheable(value=“customer”,key=”T(someType).hash(#customerCode)”)
public Customer getCustomer(String customerCode){
//….
}
}[/java]
If you would like to provide your own custom key generator, you need to implement the org.springframework.cache.KeyGenerator interface. Once done, you will have to configure the generator and the caching framework will use this new key generator for each method declaration which hasn’t specified its own key generation strategy.
Page Visitors: 12327
The following two tabs change content below.He is an Enterprise Java Specialist holding a degree in Engineering (B-Tech) with over 10 years of experience in several industries. He's currently working as Principal Architect at Emirates Group IT since 2005. Prior to this he has worked with Oracle Corporation and Ernst & Young. His main specialization is on various web technologies and acts as chief mentor and Architect to facilitate incorporating Spring as Corporate Standard in the organization.
- Shoo trackers and advertisements away - February 16, 2018
- Data, data everywhere… Prediction Four - February 14, 2018
- Data, data everywhere… Prediction Three - February 9, 2018