Home > Spring > Spring Ehcache Integration

Spring Ehcache Integration

February 26th, 2009

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

Balaji Spring ,

  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. 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. 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. 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. 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.

  1. No trackbacks yet.