Object Caching in Java with EHCache

In a project I was working on recently, we were building up a web page by loading up its template, content hierarchy and other information dynamically. This is a common setup, and a very flexible one since it allows sweeping changes to be made very easily. Unfortunately, this flexibility comes with a cost; pulling everything through EJB calls can give you a speed not unlike that of a slightly stunned tortoise trying to sprint up a treacle covered hill.

One way of mitigating this problem is to use a Facade pattern to load as much as possible with as few calls as possible. However, this is not always the best approach, especially if most of the content is not likely to change very often. In these cases, it’s preferable to store the content at the end where it’s being used, avoiding the remote call completely.

This can be implemented quickly and easily with a Map, but that would leave us with a lot of work to do when it comes to managing the cached content. For example, what if we wanted to make sure that the cache does not continue to fill up indefinitely, or that it gets backed to disk when it goes idle for some time to preserve memory?

Since we were already using Hibernate in the data layer, we were already using a cache at that level in the form of EHCache. It made sense to try and see if it was possible to use this in our controller layer, and it turned out to be extremely elegant to use.

Using EHCache

Download the demo project

EHCache is largely configuration driven, so the actual amount of code needed to use it in your application is minimal. In class SimpleCacheDemo in the example, we only need to initialize the cache and close it when the application is done:

18: CacheManager manager = CacheManager.create();

and

36: manager.shutdown();

The create method in CacheManager looks up the configuration file ehcache.xml, which should be located in the classpath, and creates a cache instance for each cache declared in the configuration. In our case, we’re declaring a single cache, called demo, which we will be using for our application.

We’re also declaring the required default cache, which is used for any caches which are created programmatically. So far, I have not needed to create caches in this way, but the option is there for anyone who needs it.

The configuration for the demo cache is minimal, and is certainly not suited for production use. It specifies a maximum time to live of 5 seconds, which means that items in the cache go stale after 5 seconds of inactivity. It will also keep a maximum of 10,000 elements in memory – overkill for the demo.

The cache is not configured to be persistent, so any elements evicted from the cache because of lack of space are just dropped. The value for memoryStoreEvictionPolicy tells the cache how to decide which items to drop. In our case it’s LRU, short for Least Recently Used. In other words, when the 10,001st object comes in, it will look over all the entries, and drop the one which has been idle for the longest time.

Accessing the Cache

Once the caches are created, we can get the instances using the manager’s getCache method, simply providing the name of the cache we need. From there, we can get elements using the cache’s get method, and put elements into the cache using its put method. It’s quite easy to remember.

The test method CachingSequenceGeneratorTestCase.shouldQueryCacheWhenRequested demonstrates the workflow.

Suppose you repeatedly need to get the nth term of a Fibonacci sequence (something I’m reliably informed happens a lot if you’re the protagonist of a certain novel, but not so much to other people) very quickly (presumably because you’re being chased by angry monks with guns). While you have a method that calculates the sequence, the developer has very helpfully made that method extremely slow.

Luckily, you can cache the results, so what happens is this:

  • You ask for a sequence of the given length.
  • The cache checks whether this is available. Since this is the first time, it will return a null.
  • The sequence is generated, cached, and returned.

Now, if you happen to need the same length again before it expires, what will happen is:

  • You ask for a sequence of the given length.
  • The cache finds the element.
  • The sequence is returned.

Since this case does not involve processing, it’s a lot faster. You can run the demo application to get some idea of the difference.

Cleaning up even further

The example application is a very simple demonstration of how to wrap an object to make it use a cache. On the other hand, we could have rewritten the generator to make full use of the cache, populating 0 .. n-1 while generating n – since it needs to do this anyway, it would hardly have any added cost, and would make subsequent access, much faster.

Then again, our aim here is to demonstrate the use of a cache, not making a super fast Fibonacci calculator for the benefit of fictional characters.

One area which I would like to explore further is the use of self-populating caches. Unlike the vanilla cache we saw in this demo, you don’t actually need to put stuff into it. When we create a self-populating cache, we can give it an object factory. If we ask it for something it doesn’t have, it pulls an instance from the factory instead. This should make the usage even cleaner.

The configuration of a distributed cache should also be interesting if I can find a suitably rainy afternoon and enough virtual machines.

Anything else?

Closing off with a note of thanks to Matthew Sant for pointing me in the direction of Mockito and reviewing the demo application.

Is there anything you would implement differently? Do you have any suggestions or tips on how to configure or use EHCache? Have you used any other caching systems which you prefer? Drop me a comment and let me know!

12 Replies to “Object Caching in Java with EHCache”

  1. Tip. Code to interfaces, e.g. FibonacciServices. Have FibonacciServicesImpl do the number crunching work. Have CachingFibonacciServicesImpl ask a self-populating EhCache for the cached sum. The CacheEntryFactory for the self-populating cache gets the sum from …. FibonacciServicesImpl. Full code reuse, and you get build-time or run-time control of whether or not to use caching, e.g. yes in production, no in unit testing, yes in integration testing.

  2. Hi Emerson, and thanks for the comment 🙂

    Even if we’re not using a self-populating cache, we’re still fully reusing code – CachingSequenceGenerator uses a provided sequence generator to draw its figures. While the example is hard coded to use the fibonacci generator, you could easily wire it up using Spring or any other DI container to take whatever generator you like.

    I’m not entirely sure I like a CachingFibonacciServicesImpl in terms of design – that class would have two concerns, not one, as opposed to the CachingSequenceGenerator which only worries about caching and lets the inner generator take care of the rest.

  3. Pingback: ehcache.net
  4. Pingback: JavaPins
  5. Probably one of the only examples you’d find on the www about caching a method in a pojo class using ehcache. I tried to find examples of this kind but i keep hitting pages that describe ehCache use as a second level cache for hibernate or it’s integration with spring. Why don’t they simply cache methods as well? Is their some underlying logic behind it? thanks for this. I keep coming back to your page often.

    1. Hello truman. What do you mean when you say “caching a method”? Are you referring to, for example, using the @Cache annotation to store the output of a method for a given set of arguments?

      I’m afraid I never really looked into doing that in any other way. In fact, it’s been a while since I wrote any non-trivial code that did not use Spring!

  6. Thanks for your reply Karl.

    When I say method caching, I simply mean using the cache for any method in java. The example that you give here isn’t restricted to a certain framework, say, like Spring. So technically, you could use Ehcache for caching results of any method, like you did, for a method that generates the Fibonacci, isn’t it? Thanks again.

  7. Downloaded the example yesterday , got a problem of dependency resolution.
    PROBLEM :
    ####################################################################

    [ERROR] Failed to execute goal on project ehcache-caching: Could not resolve dependencies for project com.simplepart.samples:ehcache-caching:jar:1.0: The following artifacts could not be resolved: javax.jms:jms:jar:1.1, com.sun.jdmk:jmxtools:jar:1.2.1, com.sun.jmx:jmxri:jar:1.2.1: Could not transfer artifact javax.jms:jms:jar:1.1 from/to java.net (https://maven-repository.dev.java.net/nonav/repository): (https://maven-repository.dev.java.net/nonav/repository%29🙂 No connector available to access repository java.net (https://maven-repository.dev.java.net/nonav/repository) of type legacy using the available factories WagonRepositoryConnectorFactory -> [Help 1]

    ####################################################################

    The solution to the same is just change your dependency tag for log4j as following:

    ###################################################################

    log4j
    log4j
    1.2.15
    compile

    com.sun.jmx
    jmxri

    com.sun.jdmk
    jmxtools

    javax.jms
    jms

    ###################################################################
    i.e , simply ignoring three jars which are not there in the maven central repository.

    In case still you face an issue , just remove all the jars from your local maven repository wihch are corrupted, this is the command to get the list of corrupted ones in linux :

    find ~/.m2 -name “*.lastUpdated” -exec grep -q “Could not transfer” {} \; -print -exec rm {} \;

  8. I am trying to store a pojo that has a list of child objects. Can I use the criteria api to get query child objects in ehcache a quick search on google has not led me anywhere. Any help would be appreciated.

    1. Good evening Abi! I’m not sure that using the criteria api in the scenario you mentioned is a good idea. You might be better served making your cache more granular, or simply caching at a higher level – in your case if you have a method like getPojosContainingChild(child), caching the output of that method would probably give you what you need. There are several different caching strategies, but in general avoid thinking of a cache as something you could query. Instead, think of it as “give me whatever result you previously got for an argument x”.

      1. Another thing, if you are already caching via the criteria rather than caching the output of the criteria api, it is likely that it is already doing what I think you want it to do.

Comments are closed.