Recently I’ve been playing around with caching within Java Web Applications; this blog describes how to use the ehcache package with Spring Beans to provide effortless caching. In this example I’m using ehcache (core) version 2.1.0 with the Spring Framework 3.0.5.

In this example we will assume we have a Spring Bean named usersBean, we need to add caching to this bean, our spring configuration for this Bean will look something like what follows:

<bean id="usersBean" class="com.hackerypokery.CachedUsers"> >
   <property name='cacheManager' ref='ehCacheManager'/>
  <property name="url" value="http://glassfish.hackerypokery.com:8080/SCIM"/>
</bean>

Our usersBean has a cacheManager, this references the ehCacheManager Spring Bean below.  The EhCacheManagerFactoryBean provides a Spring wrapper for the ehcache Framework.  The EhCacheManagerFactoryBean bean takes as input the ehcache configuration.  In our case the Cache Manager configuration is located within the ehcache.xml file on the classpath of our Web Application.  Cache Manager configuration can also be configured in-line.

<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
   <property name="configLocation">
      <value>classpath:ehcache.xml</value>
   </property>
</bean>

Our ehcache.xml configuration looks as follows:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
    <diskStore path="java.io.tmpdir/EhCacheSpringFilters" />
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
    <cache name="usersCache" eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="600" timeToLiveSeconds="1200" memoryStoreEvictionPolicy="LRU" />
</ehcache>

This configuration file sets the properties of the default cache, as well as explicitly creates a usersCache cache which we’ll use shortly, note the cache parameters are within XML allowing them to be easily tweaked without recompilation of your application or application specific properties files.  Now we have configured Spring to initialise our bean with the Spring managed ehache Framework lets look at how we can access ehcache within our application.

The CachedUsers class backs our usersBean, CachedUsers uses a Restful Web Service to retrieve users.  In our case we want to limit calling the Web Service frequently to retrieve the same user. Instead we make use of the ehcache Framework to temporarily maintain a copy of users, how temporarily is configured within the ehcache.xml file.  Our CachedUsers class takes the Cache Manager as an input, so first of all we need getters and setters for the Cache Manager:

public void setCacheManager(net.sf.ehcache.CacheManager manager)
{
    this.manager = manager;
}

public net.sf.ehcache.CacheManager getCacheManager()
{
    return manager;
}

The main body of our CachedUsers class is the retrieveUser(uid) method.  This method attempts to lookup a User object with a matching uid from the ehcache usersCache; if the User object is not found, a Restful Web Service is then called to retrieve the user.  Once a User object is retrieved via the Web Service is it stored to the usersCache.  The rerieveUser(uid) method looks as follows:

public User retrieveUser(String uid)
{
 // retrieve the user cache from the manager
 if(userCache == null) userCache = manager.getEhcache(USER_CACHE);

 // cleanup old cache entries
 userCache.evictExpiredElements();

   // check if the result is cached
   Element cached = userCache.get(uid);

   // check if the user was cached
   if(cached != null)
   {
    // the user was cached, return the user
    User user = (User)cached.getObjectValue();
    return user;
   }
   else
   {
 // check if we've setup the rest client yet
 if(client == null)
 {
 // setup the client config
 config = new ClientConfig();

 // setup the rest client
 client = new RestClient(config);

 // remove any trailing slash
 url = url.replaceAll("/$", "");
 }

 // create a resource to retrieve the user
 Resource resource = client.resource(url + "/User/" + uid);

 // request the user from the resource
 ClientResponse response = resource.get();

    // verify the response code indicates success
    int status =  response.getStatusCode();
     if(status == 200) return null;

    // retrieve the returned user entry
    User user = response.getEntity(User.class);

    // store the user to the cache for next time
    userCache.put(new Element(uid, user));
    return user;
   }
}

The important parts of the method above are: retrieving the usersCache, retrieving cached users from the usersCache and storing Restfully retrieved users to the usersCache.  The usersCache is retrieved as follows:

userCache = manager.getEhcache(USER_CACHE);

User objects are checked/retrieved from the usersCache as follows:

Element cached = userCache.get(uid);
User user = (User)cached.getObjectValue();

Where uid is a unique identifier for the user, we’re also assuming only objects of type User are being stored in this cache, be careful in real code.

User objects are stored to the usersCache as follows:

Resource resource = client.resource(url + "/User/" + uid);
ClientResponse response = resource.get();
User user = response.getEntity(User.class);
userCache.put(new Element(uid, user));

The core operation here is userCache.put(…), the rest of the code simply retrieves the user from a Restful Web Service.

You can find the complete source for the CachedUsers class here; this class uses the Apache Wink Framework to perform Restful User lookups.