Home > Spring > Spring Ehcache Integration

Spring Ehcache Integration

In this post I will share how to cache method results using Ehcache and Spring AOP. This is based on the post

The first step is to add all the required jars to the project. At minimum, the following jars should be present:

Spring and related jars (using 2.5.6 version here):

  • spring-2.5.6.jar
  • commons-logging.jar
  • commons-collections.jar
  • aspectjrt.jar
  • aspectjweaver.jar
  • jsr250-api-1.0.jar

Ehcache and its dependencies (using version 1.5.0):

  • ehcache-1.5.0.jar
  • backport-util-concurrent-3.0.jar
  • jsr107cache-1.0.jar

For the sake of this post, I will be using a DemoService with a method whose results need to be cached.

package com.inflinx.blog.service;
import java.util.List;
public interface DemoService
{
	public List getCarTypes(String filter);
}

Here is a dummy implementation of the above service:

package com.inflinx.blog.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;

@Service("demoService")
public class DemoServiceImpl implements DemoService
{

	public List getCarTypes(String filter)
	{
		List carTypes = new ArrayList();
		carTypes.add("Mini");
		carTypes.add("Economy");
		carTypes.add("Sport Utility");
		carTypes.add("Convertible");
		carTypes.add("Standard");
		
		return carTypes;
	}
}

And the application context with bean scanning turned on:




       
       
	   	       
  

The next step in the process is to add ehcache.xml to the classpath. Details on this configuration file can be found at Ehcache web site



	
     
	
	

    

Spring makes integration with Ehcache easy with EhCacheManagerFactoryBean and EhCacheFactoryBean classes. The EhCacheManagerFactoryBean provides access to Ehcache’s CacheManager and the EhCacheFactoryBean exposes caches defined in ehcache.xml.

To make use of these beans, lets add the following to the application context file:




The next step is to create an AOP Aspect that would provide caching transparently:

package com.inflinx.blog.aspect;

import javax.annotation.Resource;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component("cacheAspect")
@Aspect
@Order(2)
public class CacheAspect
{
	@Resource(name="carTypesCache")
	private Cache cache;
	
	@Around("execution(* com.inflinx.blog.service.DemoService.getCarTypes(java.lang.String))")
	public Object cacheCarTypes(ProceedingJoinPoint joinPoint) throws Throwable
	{
		Object[] arguments = joinPoint.getArgs();
		String location = (String)arguments[0];
		Element element = cache.get(location);
		if(null == element)
		{
			Object result = joinPoint.proceed();
			if(null != result)
			{
				element = new Element(location, result);
				cache.put(element);
			}
		}
		return element != null ? element.getValue() : null;
	}
}

Finally, declare the newly created aspect in the application context file:




Spring Modules provides a great alternative for declarative caching with @Cacheable annotation. As of this post, Spring Modules is still in “draft” status.

You can download the source code used in this post here

Categories: Spring Tags: ,
  1. Nes
    October 24th, 2009 at 11:37 | #1

    Great stuff and thanks for sharing. Trying to get this working myself, but running into a few problems. You sure the last code listing works?

    I get the following error when I tried:

    20:25:53,130 ERROR [ContextLoader] Context initialization failed
    org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 42 in XML document from ServletContext resource [/WEB-INF/applicationContext-ehcache.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element ‘context:component-scan’. One of ‘{“http://www.springframework.org/schema/aop”:include}’ is expected.

    Nes

  2. Balaji
    October 24th, 2009 at 11:48 | #2

    Good catch Nes. The syntax highlighter plugin I am using screwed up the code. I have updated the post now. Give it a try and let me know if you run into problems.

  3. Ramesh
    November 6th, 2009 at 13:14 | #3

    Hi,
    Nice article. Is that possible for you to share the entire Eclipse project?

    I’m new to Spring/EhCache and I’m getting several errors. Several of them are due to lower case tags in the xml and I resolved as much I know. But I would like to see how your entire code base looks like including the Main/Test code. Also how your approach is different from the approach described at http://javaboutique.internet.com/tutorials/ehcache/index-3.html?

    Thanks.

  4. Holger
    March 4th, 2010 at 07:18 | #4

    Thanks a lot for your great stuff, Balaji! This works too with Spring 3.0.x RELEASE and ehcache 1.6.x as well.

  5. rajan
    March 9th, 2010 at 09:53 | #5

    Hi Balaji
    I tried out the example above , i was able to run it sucessfully when
    as an stand alone java prog , but when i try to deploy in glass
    fish server i get an error
    NoSuchBeanDefinitionException: No bean named ‘carTypesCache’ is defined

  6. Balaji
    March 9th, 2010 at 10:04 | #6

    @Rajan
    Can you post the entire stack trace?

  7. rajan
    March 9th, 2010 at 10:54 | #7

    In continuation with my prev query this my app.xml entry

  8. rajan
    March 9th, 2010 at 10:54 | #8
  9. rajan
    March 9th, 2010 at 10:56 | #9
  10. rajan
    March 9th, 2010 at 11:01 | #10

    Balaji here is stack trace……..
    SEVERE: Exception while invoking class com.sun.enterprise.web.WebApplication start method
    java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘carTypesCache’ is defined
    at com.sun.enterprise.web.WebApplication.start(WebApplication.java:117)
    at org.glassfish.internal.data.EngineRef.start(EngineRef.java:126)
    at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:241)
    at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:236)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:339)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:183)
    at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:272)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:305)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:320)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1176)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$900(CommandRunnerImpl.java:83)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1235)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1224)
    at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:365)
    at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:204)
    at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166)
    at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:100)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:245)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
    at java.lang.Thread.run(Thread.java:619)

  11. rajan
    March 9th, 2010 at 11:02 | #11

    i have an entry for carTypesCache in app.xml

  12. Balaji
    March 9th, 2010 at 12:45 | #12

    Rajan,
    I am not able to see some of your comments. I will upload a working sample by tonight.

  13. Balaji
    March 10th, 2010 at 00:10 | #13

    @Ramesh
    @Rajan

    I have updated the post with link to the eclipse project.

  14. rajan
    March 11th, 2010 at 01:22 | #14

    Balaji any idea why org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘carTypesCache’ is defined is occuring, i find no difference in the code attached.above is my stacktrace.
    i am not able to understand why it works on standalone java prog , but not working when trying to deploy to glassfish.

  15. rajan
    March 13th, 2010 at 10:08 | #15

    Folks
    I faced the NoSuchBeanDefinitionException, just cut across the problem i removed the @Resource(name=”carTypesCache”) and physically
    got the catchManager CacheManager cacheManagerlObj = (CacheManager) appContext.getBean(“cacheManager”); to fetch the catch and set the catch attribute in CacheAspect class physically. code works now both on stand alone and also on server deployment too……. thnks balaji ,just a tip
    if somebody else faces the same problem.

  16. April 6th, 2010 at 15:56 | #16

    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

  17. Viv
    April 8th, 2010 at 16:04 | #17

    Hi Eric,
    I started with the ehcache-spring-annotations from code.google. After I added the maven dependency

    com.googlecode.ehcache-spring-annotations
    ehcache-spring-annotations
    1.0.1

    I got this error

    [ERROR] BUILD ERROR
    [INFO] ————————————————————————
    [INFO] Failed to resolve artifact.

    Missing:
    ———-
    1) javax.transaction:transaction-api:jar:1.0.1B

    Any ideas?

  18. April 8th, 2010 at 17:32 | #18

    @Viv
    You might want to post your question on project’s discussion board. Anyways, from the error, looks like jta-1.0.1B jar cannot be resolved by maven. Try installing the jar locally.

  19. April 9th, 2010 at 05:20 | #19

    The JTA library issue can be resolved by following the steps here: http://maven.apache.org/guides/mini/guide-coping-with-sun-jars.html

    I’ll update the main page for the project with this information

  20. Adeel
    October 4th, 2011 at 05:19 | #20

    Very nice.

    http://eiconsulting.blogspot.com/2011/10/ehcache-implementation-in-spring.html

    Another tutorial with detailed explaination

  1. January 2nd, 2011 at 19:52 | #1