Monday, June 6, 2011

Caching with Ehcache and Spring Annotations

I meet hundreds of developers and architects every month and they all have the same issues; performance and ability to scale.  These hard to solve problems can be solved with caching and Ehcache provides the best set of tools to quickly and easily get this done. If you are using Spring, you are well on your way to success.  I will provide you the framework to get started caching with Ehcache and Spring; the rest is up to you. 
Let's get started.  I used the Spring 3.1.0.M1 release to build my application with Ehcache 2.4.2. You can use annotations with an older version of spring. Here is the link, http://code.google.com/p/ehcache-spring-annotations/.

Here is my ehcache.xml file:




  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" 
  2.  updateCheck="false" monitoring="autodetect" dynamicConfig="true" name="Test">
  3.   <diskStore path="java.io.tmpdir"/> 


  4.   <defaultCache maxElementsInMemory="10000" 
  5.                 eternal="false" 
  6.                 timeToIdleSeconds="120" 
  7.                 timeToLiveSeconds="120" 
  8.                 memoryStoreEvictionPolicy="LRU" />


  9.     <cache name="Person"
  10.     maxElementsInMemory="100" 
  11.   eternal="true" 
  12.         maxElementsOnDisk="1000" 
  13.   memoryStoreEvictionPolicy="LFU">
  14.  </cache> 
  15. </ehcache>


Call this ehcache.xml file from your Spring context file.




  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.  xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
  4.  xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.  xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
  6.  xmlns:cache="http://www.springframework.org/schema/cache"
  7.  xsi:schemaLocation="
  8.             http://www.springframework.org/schema/beans
  9.             http://www.springframework.org/schema/beans/spring-beans.xsd
  10.             http://www.springframework.org/schema/aop
  11.             http://www.springframework.org/schema/aop/spring-aop.xsd
  12.             http://www.springframework.org/schema/tx
  13.             http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  14.             http://www.springframework.org/schema/jdbc
  15.             http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
  16.             http://www.springframework.org/schema/context
  17.             http://www.springframework.org/schema/context/spring-context-3.0.xsd
  18.             http://www.springframework.org/schema/cache 
  19.             http://www.springframework.org/schema/cache/spring-cache.xsd">

  20.   <!-- scans the classpath for annotated components (including @Repostory 
  21.   and @Service that will be auto-registered as Spring beans -->
  22.  <context:component-scan base-package="com.sample.ehcache" />

  23.   <!-- Process cache annotations -->
  24.  <cache:annotation-driven />

  25.   <!-- Configuration for using Ehcache as the cache manager -->
  26.  <bean 
  27.   id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" 
  28.   p:cache-manager-ref="ehcache"/> 
  29.   <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" 
  30.   p:config-location="classpath:ehcache.xml"/> 
  31. </beans>


The power of the Spring context file is component-scan, annotation-driven and the Ehache entries. The component-scan tells Spring to scan these directories for beans that will be auto registered. Annotation driven turns on the annotations to use with Ehcache.

Next I create a base object that my data access object implement.




  1. public interface BaseDao {
  2.  
  3. /**
  4.   * Using the provided key return
  5.   * the associated Object from the data
  6.   * repository.
  7.   * @param key
  8.   * @return object having the associated key or
  9.   * null if no associated Object is found with the provided
  10.   * key
  11.   */
  12. Object getObject(String key);
  13.  
  14. /**
  15.   * Clears all objects
  16.   */
  17. void clearObjects();
  18.  
  19. /**
  20.   * clears object by key
  21.   * @param key
  22.   */
  23. void clearObject(String key);
  24. }


I implement the BaseDao in the following class and then add the @Cacheable and @CacheEvict annotations.  It is just this simple.




  1. @Repository("baseDao")
  2. public class PersonDaoImpl implements BaseDao {

  3.  private static final Logger LOGGER = Logger.getLogger(PersonDaoImpl.class.getName());

  4.   /**
  5.   * The @Cacheable automatically puts the data in the cache
  6.   */
  7.  @Cacheable("Person", key="#key")
  8.  public final Person getObject(String key) {  
  9.   
  10.   Person person = buildPerson(key);
  11.   return person;  
  12.  }

  13.  //stubbed data building
  14.  private static Person buildPerson(String key) {
  15.   LOGGER.debug("Building new Person object");
  16.   
  17.   Person person = new Person();
  18.   person.setPersonId(key);
  19.   person.setFirstName("Joe");
  20.   person.setLastName("Smith");
  21.   return person;
  22.  }

  23.   @CacheEvict(value="Person", allEntries=true)
  24.  public void clearObjects() {
  25.   LOGGER.debug("Person cache evicted...."); 
  26.  }

  27.  @CacheEvict(value="Person", key="#key")
  28.  public void clearObject(String key) {
  29.   LOGGER.debug("Person cache evicted...."); 
  30.  }
  31. }


That is it! Now your data objects are cached on retrieval (doesn't matter where you get the data from) and your application performance will soar to new heights (and so will your status with your peers).  Simple caching is just the beginning. There are loads of great features in Ehcache like Search, JTA, Write-Behind, and many more. Check out the Ehcache web site, www.ehcache.org,  to get the full list of features.


No comments:

Post a Comment