Introducing Cache support in Spring 3.1 M1

spring-logoSpring 3.1 M1 is out with some very useful features. One of the coolest feature in the latest release is comprehensive Caching support! Spring Framework provides support for transparently adding caching into an existing Spring application. Similar to the transaction support, the caching abstraction allows consistent use of various caching solutions with minimal impact on the code. The cache is applied to Java methods, reducing the number of executions based on the information available. Spring checks if the given method is already executed for given set of parameters. If the method is already executed, Spring uses the cache value and returns it to caller instead of calling the method again. This is a write through cache. This way, expensive methods (whether CPU or IO bound) can be executed only once for a given set of parameters and the result reused without having to actually execute the method again. The caching logic is applied transparently without any interference to the invoker.

Adding Cache support to Spring project

In order to add Cache support to any Spring based project, one needs to declare the configuration using new Spring tag in the schema declaration.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <cache:annotation-driven /> ... </beans>
Code language: HTML, XML (xml)
Note the cache:annotation-driven tag in above declaration enables the caching in given Spring project.

Using @Cacheable and @CacheEvict annotations

Spring 3.1 M1 provides two very useful Java annotations: @Cacheable and @CacheEvict which allow methods to trigger cache population or cache eviction. Let us take a closer look at each annotation:

@Cacheable annotation

This annotation mark a method cacheable. Thus the result from this method call will be stored into the cache on subsequent invocations with same arguments.
@Cacheable("persons") public Person profile(Long personId) { ... }
Code language: Java (java)
In the above code snippet, method profile is marked cacheable using @Cacheable annotation. Also the method is associated with a cache named “persons“. Whenever method profile is called, the Spring framework will check if cached entry is available in persons cache and returns the same without calling profile method. It is also possible to provide multiple cache names if you have multiple caches declared in your application. For example:
@Cacheable({"persons", "profiles"}) public Person profile(Long personId) { ... }
Code language: Java (java)
In above code snippet, we provide two cache names persons and profiles. Spring framework will check in all the caches if entry is available for given method call with argument personId, if at least one cache is hit, then the associated value will be returned.

@CacheEvict annotation

Cache eviction is removing of any unused or stale data from the cache. Opposed to @Cacheable, annotation @CacheEvict demarcates methods that perform cache eviction, that is methods that act as triggers for removing data from the cache. Just like its sibling, @CacheEvict requires one to specify one (or multiple) caches that are affected by the action, allows a key or a condition to be specified but in addition, features an extra parameter allEntries which indicates whether a cache-wide eviction needs to be performed rather then just an entry one (based on the key):
@CacheEvict (value = "persons", allEntries=true) public List<Person> listPersons()
Code language: Java (java)
This annotation is very useful when an entire cache region needs to be cleared out. The Spring framework will ignore any key specified in this scenario as it does not apply.

Using Default key

The cache is nothing but a key-value store which stores the data based on certain key. In Spring framework based caching, the method arguments of cached method acts as the source of Key generation. Every key is essentially the Hash-code of these arguments. This approach works well for objects with natural keys as long as the hashCode() reflects that. If that is not the case then for distributed or persistent environments, the strategy needs to be changed as the objects hashCode is not preserved. In fact, depending on the JVM implementation or running conditions, the same hashCode can be reused for different objects, in the same VM instance. To provide a different default key generator, one needs to implement the org.springframework.cache.KeyGenerator interface. Once configured, the generator will be used for each declaration that does not specify its own key generation strategy. By default, all the method arguments are used in Key generation logic. In practice not all methods have only one argument or, worse yet, the parameters are not suitable as cache keys – take for example a variation of the method above:
@Cacheable(value="persons", key="personId") public Person profile(Long personId, Long groundId) { ... }
Code language: Java (java)
Here we are using just personId in key generation ignoring groupId altogether.

Understand Conditional caching

Spring framework also supports conditional caching letting user to cache certain methods based on some conditions. For example, in following code snippet we cache profiles only for those users who have profileId greater than 50:
@Cacheable(value="persons", condition="personId > 50") public Person profile(Long personId) { ... }
Code language: Java (java)

Currently supported libraries

There are probably hundreds of cache libraries available which can be used in your JEE project. For now the Spring framework supports following implementations:
  1. JDK ConcurrentMap based Cache
  2. Ehcache based Cache

JDK ConcurrentMap based Cache

The JDK-based Cache implementation resides under org.springframework.cache.concurrent package. It allows one to use ConcurrentHashMap as a backing Cache store.
<!-- generic cache manager --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/> <bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="persons"/> </set> </property> </bean>
Code language: HTML, XML (xml)
In above code snippet, we use SimpleCacheManager class to create a CacheManager. Note that we have created two caches in our application, one is default and second is persons.

Ehcache based Cache

The Ehcache implementation is located under org.springframework.cache.ehcache package. Again, to use it, one simply needs to declare the appropriate CacheManager:
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhcacheCacheManager" p:cache-manager="ehcache"/> <!-- Ehcache library setup --> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>
Code language: HTML, XML (xml)
This setup bootstraps ehcache library inside Spring IoC (through bean ehcache) which is then wired into the dedicated CacheManager implementation. Note the entire ehcache-specific configuration is read from the resource ehcache.xml.

References

Get our Articles via Email. Enter your email address.

You may also like...

13 Comments

  1. Angus says:

    org.springframework.cache.ehcache.EhCacheCacheManager
    NOT
    org.springframework.cache.ehcache.EhcacheCacheManager

  2. rohid says:

    2 Corrections need to be made to the example above

    the issues are:
    1. EhCacheCacheManager (note the 2 C capitals)
    2. p:cache-manager-ref=”ehcache” (p:cache-manager-ref not p:cache-manager)
    3. to use p:

    I spent many trying to solve this.
    Regards,
    Rohid

  3. Sameer says:

    How can we make it to reload all data into cache memory ??

  4. Lukasz says:

    Spring cache abstraction is broken, as it doesn’t account for hash collisions, i.e. given below signature:

    @Cacheable("myCache")
    int a(int a, String s)
    

    a(1, “FB”) will hash to the same key as a(1, “Ea”), when using the default key generator. The issue is that the cache abstraction doesn’t take advantage of equality test. In other words, the key should be an object, which implements hashCode()/equals(), not a hash.

    • Hi Lukasz,

      I am sure that using default key generation is not a good idea as it will always have a hashCode limitation. By all means we can create our own custom key using SePL which spring caching utilizes.

      Regards
      Niraj

  5. Hi Viral,

    This is an excellent post. Have you explored key generation strategies, will love to hear your experiences on them. I have written a similar post but I have used memcached as an example. I have used your post as reference. I hope you don’t mind me putting this link here.
    http://weblog4j.com/2013/05/31/simple-spring-memcached-spring-caching-abstraction-and-memcached/

    Niraj

  6. sudha says:

    If my cache function has no arguments means, what will happen?

    for example

    @Cacheable(value=”infortuniAttivitaDetail”)
    public List getInfortuniAttivitaDetail()
    {

    }

    will it be a problem?

    thanks

  7. Rakesh says:

    Hi Viral,
    Do you have any example for spring cache with aspectj mode and compile time weaving?

    I am using following configuration however caching is taking effect. Things work fine if I switch back to proxy mode…

  8. Mohan Kamboj says:

    Name of class is EhCacheCacheManager not this org.springframework.cache.ehcache.EhcacheCacheManager

    and maven depency is

    org.springframework
    spring-context-support
    3.2.2.RELEASE

  9. Veda says:

    http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/cache.html

    Use

    @org.springframework.cache.annotation.EnableCaching 

    for Spring Java based configuration.

  10. sekhar says:

    Hi viral

    can you please give me an example to get data from database whileserver start up and store it in cache and we have to use when ever we want in programe by using spring cache can you please post an example or suggest me any example

  11. ciao says:

    You should change ConcurrentCacheFactoryBean to ConcurrentMapCacheFactoryBean

  12. Biswajit Mohapatra says:

    Nice tutorial for beginners and well explanation. It is very useful and helped me .

Leave a Reply

Your email address will not be published. Required fields are marked *