Integrating Spring and EHCache

Using Spring Modules and EHCache, one can transparently cache method results. Spring Modules uses a proxy which intercepts call to the method of bean; consults the cache to check if method was called with same parameters before, if so will return cached result.
EHCache is the actual provider of caching solution and Spring Module handles method interception and result storing in cache.
Since I am using Maven2, so added following dependancies –
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.springmodules</groupId> <artifactId>spring-modules-cache</artifactId> <version>0.9</version> </dependency>
My complete pom.xml –
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Spring</groupId> <artifactId>Spring</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.springmodules</groupId> <artifactId>spring-modules-cache</artifactId> <version>0.9</version> </dependency> </dependencies> </project>
Contact Table sql –
CREATE TABLE `contact` ( `ID` int(15) NOT NULL AUTO_INCREMENT, `FIRSTNAME` varchar(50) DEFAULT NULL, `LASTNAME` varchar(50) DEFAULT NULL, `EMAIL` varchar(150) DEFAULT NULL, PRIMARY KEY (`ID`), UNIQUE KEY `EMAIL` (`EMAIL`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
Adding ehcache namespace to Spring config file –
<?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:aop="http://www.springframework.org/schema/aop" xmlns:ehcache="http://www.springmodules.org/schema/ehcache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> ... </beans>
Created ehcache.xml file in classpath.
<ehcache> <defaultCache maxElementsInMemory="500" eternal="true" overflowToDisk="false" memoryStoreEvictionPolicy="LFU"/> <cache name="contactCache" maxElementsInMemory="500" eternal="true" overflowToDisk="false" memoryStoreEvictionPolicy="LFU"/> </ehcache>
Adding caching to application-context.xml –
<?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:aop="http://www.springframework.org/schema/aop" xmlns:ehcache="http://www.springmodules.org/schema/ehcache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <ehcache:config configLocation="classpath:ehcache.xml" /> <ehcache:proxy id="contactDAO" refId="contactDAOTarget"> <ehcache:caching cacheName="contactCache" methodName="findAll"/> <ehcache:flushing cacheNames="contactCache" methodName="createContact" when="after"/> </ehcache:proxy> <bean id="contactDAOTarget" class="byteco.de.spring.ContactDAOImpl"> <property name="namedParameterJdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="username" value="root"/> <property name="password" value="password"/> <property name="initialSize" value="5"/> <property name="url" value="jdbc:mysql://localhost:3306/springjpa"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg type="javax.sql.DataSource" ref="datasource"/> </bean> </beans>
Here is my test class –
package byteco.de.spring; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.test.annotation.ExpectedException; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = "/application-context.xml") public class ContactDAOTest { @Autowired ContactDAO contactDAO; @Test public void shouldCreateNewContact(){ assertTrue(contactDAO.createContact("gabbar","singh","gabbar@singh.com")); assertTrue(contactDAO.createContact("kalia","singh","kalia@singh.com")); } @Test public void shouldReturnListOfContact(){ assertTrue(contactDAO.findAll().size()>0); assertTrue(contactDAO.findAll().size()>0); assertTrue(contactDAO.findAll().size()>0); // This will cause the cache to be cleared. refer to logs. assertTrue(contactDAO.createContact("samba","singh","samba@singh.com")); assertTrue(contactDAO.findAll().size()>0); assertTrue(contactDAO.findAll().size()>0); assertTrue(contactDAO.findAll().size()>0); } }
Executed test shouldCreateNewContact first then shouldReturnListOfContact. Below is the console output –
DEBUG [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor] - Autowiring by type from bean name 'byteco.de.spring.ContactDAOTest' to bean named 'contactDAO' DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0' DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0' DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to retrieve a cache entry using key <2056181503|2056171012> and cache model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <null> DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL query DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [select * from contact] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to store the object <[0. 1 gabbar singh , 1. 2 kalia singh ]> in the cache using key <2056181503|2056171012> and model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Object was successfully stored in the cache DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to retrieve a cache entry using key <2056181503|2056171012> and cache model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <[0. 1 gabbar singh , 1. 2 kalia singh ]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to retrieve a cache entry using key <2056181503|2056171012> and cache model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <[0. 1 gabbar singh , 1. 2 kalia singh ]> DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL update DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [insert into contact (firstname,lastname,email) values (?,?,?)] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource DEBUG [org.springframework.jdbc.core.JdbcTemplate] - SQL update affected 1 rows DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to flush the cache using model <org.springmodules.cache.provider.ehcache.EhCacheFlushingModel@2dd59d3c[cacheNames={'contactCache'}, flushBeforeMethodExecution=false]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Cache has been flushed. DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to retrieve a cache entry using key <2056181503|2056171012> and cache model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <null> DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL query DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [select * from contact] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to store the object <[0. 1 gabbar singh , 1. 2 kalia singh , 2. 3 samba singh ]> in the cache using key <2056181503|2056171012> and model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Object was successfully stored in the cache DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to retrieve a cache entry using key <2056181503|2056171012> and cache model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <[0. 1 gabbar singh , 1. 2 kalia singh , 2. 3 samba singh ]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Attempt to retrieve a cache entry using key <2056181503|2056171012> and cache model <org.springmodules.cache.provider.ehcache.EhCacheCachingModel@1531164[cacheName='contactCache', blocking=false, cacheEntryFactory=null]> DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <[0. 1 gabbar singh , 1. 2 kalia singh , 2. 3 samba singh ]>
Here are my DAO classes –
package byteco.de.spring; import java.util.List; public interface ContactDAO { boolean createContact(String firstName, String lastName, String email); List findAll(); }
package byteco.de.spring; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; public class ContactDAOImpl implements ContactDAO { private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) { this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; } public boolean createContact(String firstName, String lastName, String email) { Map<String,String> map = new HashMap<String, String>(); map.put("firstname",firstName); map.put("lastname",lastName); map.put("email",email); int i = namedParameterJdbcTemplate.update("insert into contact (firstname,lastname,email) values (:firstname,:lastname,:email)", map); return i>0; } public List findAll() { return namedParameterJdbcTemplate.query("select * from contact", (Map<String, ?>) null, new RowMapper() { public Object mapRow(ResultSet resultSet, int i) throws SQLException { return i + ". " + resultSet.getString(1) + " " + resultSet.getString(2) + " " + resultSet.getString(3) + " "; } }); } }
We are caching the result of findAll and clearing cache when createContact is executed.
Comments
Trackbacks
- 2lips.pl – pasja programowania » Blog Archive » Memoization with ehcache and spring
- Great tutorial on wiring EHCache into your app with Spring
Christian Herta
February 20th
thanks for your nice tutorial. But I just wondering why you example works in this way. I got an exception “no class def found” for EhCacheManagerFactoryBean.
After adding the following dependency to the maven pom it seems to work:
org.springframework
spring-context-support
3.0.0.RELEASE
Eric Dalquist
April 15th
I am one of the authors of a new project intended to provide Ehcache integration for Spring 3 projects via annotations:
http://code.google.com/p/ehcache-spring-annotations/
We are excited to announce the general availability of the first production release, 1.0.1.
This release provides 2 method-level annotations in the spirit of Spring’s @Transactional:
@Cacheable
@TriggersRemove
When appropriately configured in your Spring application, this project will create caching aspects at runtime around your @Cacheable annotated methods.
Usage documentation can be found on the project wiki:
http://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheAnnotations
http://code.google.com/p/ehcache-spring-annotations/wiki/UsingTriggersRemove
Venkat
May 10th
This is great tutorial. Especially the way the dependencies are explained and the way the dependent xsds are defined is great. Kudos to your time and effort.
Thanks,
Venkat
rabbit
September 13th
Hi, Very nice tutorial.
Could you help me out in getting the logs for springmodules ?
Here is my log4j.properties entry :
log4j.category.org.springmodules=debug, appTest
log4j.additivity.org.springmodules.cache=false
log4j.appender.appTest=org.apache.log4j.ConsoleAppender
log4j.appender.appTest.threshold=DEBUG
log4j.appender.appTest.layout=org.apache.log4j.PatternLayout
log4j.appender.appTest.layout.ConversionPattern=%p %d{HH:mm:ss,SSS} %c{2} – %m%n
I have made the changes as mentioned above. My Junit test runs, but there are no messages from ehcache which come up on the console. So there is no way for me to verify if it is really working.
Thanks in advance.
xavi
February 21st
I’ve seen the version of ehcache is 1.6.1 and springmodules 0.9. Do you know which are the updated ones? I’m trying to compile with the information on the ehcache website:
net.sf.ehcache
ehcache
2.3.1
pom
But it doesn’t work because there’s some pom that doesn’t has this high version (ehcache-terracotta, on the maven repository the last version is 2.1.1). I can’t even build the project!
Thanks in advanced!
adeel
October 4th
Very nice.
http://eiconsulting.blogspot.com/2011/10/ehcache-implementation-in-spring.html
Another tutorial with detailed explaination
Josh
November 9th
Hello, thanks for this great tutorial. How would you integrate transaction management into this example as well?
Anurag
January 11th
Nice Tutorial sir.. but actually will u provide some more details example form which i can implement in my apps..
Add Yours
YOU