Monday, December 26, 2011

Spring3.1- Caching Abstraction

The latest  release of Spring3.1 includes Caching abstraction support in the framework .This enable developers to use various caching solutions with minimal impact on code .To use this feature developer needs to do two things
  • Cache Declaration -  Identification of methods that needs caching 
  • Cache Configuration - backing cache where the data is stored and read from 
I took simple standalone java program as example for learning purpose .This involves the following
  • CacheTestClient.java  - Java Main program
  • EmployeeService.java - Cache declaration is present 
  • Employee.java - Simple POJO which needs to be cached 
  • cache-config.xml - Application context which holds bean definition for the above classes .
We are going to walk through each entities that are mentioned above to get clear understanding of their responsilbilities

Employee.java -  POJO and it is self-explanatory 

package com.works.sample.model;

public class Employee {
private String name;
private String emailAddress;
private String id;
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
EmployeeService.java - This is service layer class which contains business method such as findEmployee().This method just instantiate  Employee object first time and place it in cache with key "employee" .If the method gets invoked second time with same parameters it just retrieves from cache .For making this happen ,we have to annotate the method with "@Cacheable" which accepts parameter as key name


package com.works.caching.service;


import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import com.works.sample.model.Employee;


public class EmployeeService {

@Cacheable("employee")
public Employee findEmployee(String id){
System.out.println("Inside findEmployee !!!!");
Employee employee = new Employee();
employee.setEmailAddress("ns.rags@gmail.com");
employee.setName("Raghavan");
return  employee;
}

@CacheEvict(value ="employee",allEntries=true)
public void loadEmployee(Employee employee){
System.out.println("Evicting the Cache .....");
}

}


cache-config.xml  - This is application context configuration file which contains bean definitions for service classes and backing cache. The configuration involves the folllowing 
  • Enable caching 
    • Involves cache annotations to be enabled by <cache:annotation-driven/>
  • Configure Cache Manager & Configure Cache Store
    • SimpleCacheManager - Spring Implementation for simple cache
    • ConcurrentMap - cache for storing objects 
  • Declare Caching
    • Annotate the required service method with "@Cacheable" as mentioned in EmployeeService
We can also prefer other caching solutions such as EhCache ,etc .But at this point of writing only Ehcache is supported by  spring and any custom cache solutions can also be plugged by following  guideline outlined in their reference guide. The entire cache-config.xml will look as below
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
   <cache:annotation-driven/>
<bean id="employeeService" class="com.works.caching.service.EmployeeService"/>
<bean id="employeeClient" class="com.works.caching.client.CacheTestClient">
<property name="employeeService" ref="employeeService"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
      <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="default"/>
    </set>
</property>
</bean>
</beans>
CacheTestClient.java - Client program responsible for instantiating application context and invoking service method 

package com.works.caching.client;


import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.works.caching.service.EmployeeService;
import com.works.sample.model.Employee;


public class CacheTestClient {

private EmployeeService employeeService;

public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-config/cache-config.xml");
CacheTestClient empClient = (CacheTestClient) context.getBean("employeeClient");
empClient.employeeService.findEmployee("123239");
System.out.println("Invoking findEmployee next time to see if it's from Cache ....");
empClient.employeeService.findEmployee("123239");
empClient.employeeService.loadEmployee(new Employee());
System.out.println("Lookup to see if cache Exists which ideally won't ....");
empClient.employeeService.findEmployee("123239");

}

}


From the above snippet the first method call will instantiate Employee object whereas second one will serve from cache "employee".Also in order to clear the cache i have used @CacheEvict(value="employee",allEntries=true) so that all entries in the cache "employee" will be cleared .Once cleared when i try lookup the Employee object using id=123239 which doesn't exist  anymore .So it re-creates the object and returns it back . Please find source code for the above example

Happy learning!!!!!

1 comment:

  1. hi raghavan,very interesting blog about caching.. but how about if we use AtomicReference for caching? currently im using this concept of AtomicReference. Which is the best one to use for caching?

    ReplyDelete