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. 01. < dependency > 02. < groupId >net.sf.ehcache</ groupId > 03. < artifactId >ehcache</ artifactId > 04. < version >1.6.1</ version > 05. </ dependency > 06. < dependency > 07. < groupId >org.springmodules</ groupId > 08. < artifactId >spring-modules-cache</ artifactId > 09. < version >0.9</ version > 10. </ dependency > My complete pom.xml - 01. <? xml version = "1.0" encoding = "UTF-8" ?> 05. < modelVersion >4.0.0</ modelVersion > 06. < groupId >Spring</ groupId > 07. < artifactId >Spring</ artifactId > 08. < version >1.0</ version > 09. < dependencies > 10. < dependency > 11. < groupId >org.springframework</ groupId > 12. < artifactId >spring-core</ artifactId > 13. < version >3.0.0.RELEASE</ version > 14. </ dependency > 15. < dependency > 16. < groupId >junit</ groupId > 17. < artifactId >junit</ artifactId > 18. < version >4.7</ version > 19. </ dependency > 20. < dependency > 21. < groupId >org.springframework</ groupId > 22. < artifactId >spring-test</ artifactId > 23. < version >3.0.0.RELEASE</ version > 24. </ dependency > 25. < dependency > 26. < groupId >org.springframework</ groupId > 27. < artifactId >spring-beans</ artifactId > 28. < version >3.0.0.RELEASE</ version > 29. </ dependency > 30. < dependency > 31. < groupId >org.springframework</ groupId > 32. < artifactId >spring-context</ artifactId > 33. < version >3.0.0.RELEASE</ version > 34. </ dependency > 35. < dependency > 36. < groupId >cglib</ groupId > 37. < artifactId >cglib</ artifactId > 38. < version >2.2</ version > 39. </ dependency > 40. < dependency > 41. < groupId >org.springframework</ groupId > 42. < artifactId >spring-aop</ artifactId > 43. < version >3.0.0.RELEASE</ version > 44. </ dependency > 45. < dependency > 46. < groupId >org.aspectj</ groupId > 47. < artifactId >aspectjweaver</ artifactId > 48. < version >1.6.6</ version > 49. </ dependency > 50. < dependency > 51. < groupId >mysql</ groupId > 52. < artifactId >mysql-connector-java</ artifactId > 53. < version >5.1.10</ version > 54. </ dependency > 55. < dependency > 56. < groupId >commons-dbcp</ groupId > 57. < artifactId >commons-dbcp</ artifactId > 58. < version >1.2.2</ version > 59. </ dependency > 60. < dependency > 61. < groupId >org.springframework</ groupId > 62. < artifactId >spring-jdbc</ artifactId > 63. < version >3.0.0.RELEASE</ version > 64. </ dependency > 65. < dependency > 66. < groupId >net.sf.ehcache</ groupId > 67. < artifactId >ehcache</ artifactId > 68. < version >1.6.1</ version > 69. </ dependency > 70. < dependency > 71. < groupId >org.springmodules</ groupId > 72. < artifactId >spring-modules-cache</ artifactId > 73. < version >0.9</ version > 74. </ dependency > 75. </ dependencies > 76. </ project > Contact Table sql - 1. CREATE TABLE `contact` ( 2. `ID` int (15) NOT NULL AUTO_INCREMENT, 3. `FIRSTNAME` varchar (50) DEFAULT NULL , 4. `LASTNAME` varchar (50) DEFAULT NULL , 5. `EMAIL` varchar (150) DEFAULT NULL , 6. PRIMARY KEY (`ID`), 7. UNIQUE KEY `EMAIL` (`EMAIL`) 8. ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 Adding ehcache namespace to Spring config file - 01. <? xml version = "1.0" encoding = "UTF-8" ?> 08. ... 09. </ beans > Created ehcache.xml file in classpath. 1. < ehcache > 2. < defaultCache 3. maxElementsInMemory = "500" eternal = "true" overflowToDisk = "false" memoryStoreEvictionPolicy = "LFU" /> 4. < cache name = "contactCache" maxElementsInMemory = "500" eternal = "true" overflowToDisk = "false" 5. memoryStoreEvictionPolicy = "LFU" /> 6. </ ehcache > Adding caching to application-context.xml – 01. <? xml version = "1.0" encoding = "UTF-8" ?> 08. 09. < ehcache:config configLocation = "classpath:ehcache.xml" /> 10. 11. < ehcache:proxy id = "contactDAO" refId = "contactDAOTarget" > 12. < ehcache:caching cacheName = "contactCache" methodName = "findAll" /> 13. < ehcache:flushing cacheNames = "contactCache" methodName = "createContact" when = "after" /> 14. </ ehcache:proxy > 15. 16. < bean id = "contactDAOTarget" class = ".spring.ContactDAOImpl" > 17. < property name = "namedParameterJdbcTemplate" ref = "jdbcTemplate" ></ property > 18. </ bean > 19. 20. < bean id = "datasource" class = "org.apache.commons.dbcp.BasicDataSource" > 21. < property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> 22. < property name = "username" value = "root" /> 23. < property name = "password" value = "password" /> 24. < property name = "initialSize" value = "5" /> 26. </ bean > 27. 28. < bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" > 29. < constructor-arg type = "javax.sql.DataSource" ref = "datasource" /> 30. </ bean > 31. </ beans > Here is my test class - 01. package .spring; 02. 03. import org.junit.Test; 04. import org.junit.runner.RunWith; 05. import org.springframework.beans.factory.annotation.Autowired; 06. import org.springframework.dao.DuplicateKeyException; 07. import org.springframework.test.annotation.ExpectedException; 08. import org.springframework.test.context.ContextConfiguration; 09. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 10. 11. import java.util.List; 12. 13. import static org.junit.Assert.assertTrue; 14. 15. @RunWith (SpringJUnit4ClassRunner. class ) 16. @ContextConfiguration (value = "/application-context.xml" ) 17. public class ContactDAOTest { 18. 19. @Autowired 20. ContactDAO contactDAO; 21. 22. @Test 23. public void shouldCreateNewContact(){ 24. assertTrue(contactDAO.createContact( "gabbar" , "singh" , "gabbar@singh.com" )); 25. assertTrue(contactDAO.createContact( "kalia" , "singh" , "kalia@singh.com" )); 26. } 27. 28. @Test 29. public void shouldReturnListOfContact(){ 30. assertTrue(contactDAO.findAll().size()> 0 ); 31. assertTrue(contactDAO.findAll().size()> 0 ); 32. assertTrue(contactDAO.findAll().size()> 0 ); 33. // This will cause the cache to be cleared. refer to logs. 34. assertTrue(contactDAO.createContact( "samba" , "singh" , "samba@singh.com" )); 35. assertTrue(contactDAO.findAll().size()> 0 ); 36. assertTrue(contactDAO.findAll().size()> 0 ); 37. assertTrue(contactDAO.findAll().size()> 0 ); 38. } 39. } Executed test shouldCreateNewContact first then shouldReturnListOfContact. Below is the console output - 01. DEBUG
[org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor]
- Autowiring by type from bean name '.spring.ContactDAOTest'
to bean named 'contactDAO' 02. DEBUG
[org.springframework.beans.factory.support.DefaultListableBeanFactory] -
Returning cached instance of singleton bean
'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0' 03. DEBUG
[org.springframework.beans.factory.support.DefaultListableBeanFactory] -
Returning cached instance of singleton bean
'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0' 04. 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]> 05. DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <null> 06. DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL query 07. DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [select * from contact] 08. DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource 09. DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource 10. 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]> 11. DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Object was successfully stored in the cache 12. 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]> 13. DEBUG
[org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved
cache element <[0. 1 gabbar singh , 1. 2 kalia singh ]> 14. 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]> 15. DEBUG
[org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved
cache element <[0. 1 gabbar singh , 1. 2 kalia singh ]> 16. DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL update 17. DEBUG
[org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL
statement [insert into contact (firstname,lastname,email) values
(?,?,?)] 18. DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource 19. DEBUG [org.springframework.jdbc.core.JdbcTemplate] - SQL update affected 1 rows 20. DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource 21. 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]> 22. DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Cache has been flushed. 23. 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]> 24. DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved cache element <null> 25. DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL query 26. DEBUG [org.springframework.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [select * from contact] 27. DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource 28. DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource 29. 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]> 30. DEBUG [org.springmodules.cache.provider.ehcache.EhCacheFacade] - Object was successfully stored in the cache 31. 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]> 32. DEBUG
[org.springmodules.cache.provider.ehcache.EhCacheFacade] - Retrieved
cache element <[0. 1 gabbar singh , 1. 2 kalia singh , 2. 3 samba
singh ]> 33. 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]> 34. 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 – 1. package .spring; 2. import java.util.List; 3. public interface ContactDAO { 4. boolean createContact(String firstName, String lastName, String email); 5. List findAll(); 6. } 01. package .spring; 02. 03. import org.springframework.jdbc.core.JdbcTemplate; 04. import org.springframework.jdbc.core.RowMapper; 05. import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 06. 07. import java.sql.ResultSet; 08. import java.sql.SQLException; 09. import java.util.HashMap; 10. import java.util.List; 11. import java.util.Map; 12. 13. public class ContactDAOImpl implements ContactDAO { 14. 15. private NamedParameterJdbcTemplate namedParameterJdbcTemplate; 16. 17. public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) { 18. this .namedParameterJdbcTemplate = namedParameterJdbcTemplate; 19. } 20. 21. public boolean createContact(String firstName, String lastName, String email) { 22. Map<String,String> map = new HashMap<String, String>(); 23. map.put( "firstname" ,firstName); 24. map.put( "lastname" ,lastName); 25. map.put( "email" ,email); 26. int i = namedParameterJdbcTemplate.update( "insert into contact (firstname,lastname,email) values (:firstname,:lastname,:email)" , map); 27. return i> 0 ; 28. } 29. 30. public List findAll() { 31. return namedParameterJdbcTemplate.query( "select * from contact" , (Map<String, ?>) null , new RowMapper() { 32. public Object mapRow(ResultSet resultSet, int i) throws SQLException { 33. return i + ". " + resultSet.getString( 1 ) + " " + resultSet.getString( 2 ) + " " + resultSet.getString( 3 ) + " " ; 34. } 35. }); 36. } 37. } We are caching the result of findAll and clearing cache when createContact is executed. |
|