Spring 3.1 Cache Abstraction Tutorial

One of the new features introduced in the forthcoming Spring 3.1 version is the one of cache abstraction.

Spring Framework provides support for transparently adding caching into an existing Spring application. Similar to the transaction support, the caching abstraction allows consistent use of various caching solutions with minimal impact on the code.

At its core, the abstraction applies caching to Java methods, reducing thus the number of executions based on the information available in the cache. That is, each time a targeted method is invoked, the abstraction will apply a caching behaviour checking whether the method has been already executed for the given arguments. If it has, then the cached result is returned without having to execute the actual method; if it has not, then method is executed, the result cached and returned to the user so that, the next time the method is invoked, the cached result is returned.

This concept is of course not something new. You can check out Spring, AspectJ, Ehcache Method Caching Aspect a very interesting post from Brian Du Preez, one of our JCG partners, in which Aspect Oriented Programming is used.

As its name implies, Cache Abstraction is not an actual implementation, so it requires the use of an actual storage to store the cache data. As you might have guessed, Ehcache support is provided out of the box. There is also an implementation based on JDK’s ConcurrentMap and you can actually plug-in different back-end caches.

Now, let’s see some sample code on caching abstraction. For this purpose, I will use the very informative Cache Abstraction in Spring 3.1.0.M1 post by James Carr, another of our JCG partners. Make sure to bookmark the Spring Cache package Javadocs along the way.

(NOTE: The original post has been slightly edited to improve readability)

Another new feature released yesterday came in parallel with me trying out some annotation based caching strategies. Caching Abstraction basically takes convention from an existing project and makes it part of Spring core.

Essentially it introduces a new interface, CacheManager, which can be implemented by a specific cache implementation. From there it adds a few new annotations to make methods cacheable. Here’s an example using my previous posts objects.

package com.jamescarr.example;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;

@Repository
public class MemoryMessageRepository implements MessageRepository {

    private static final Logger LOG =
           LoggerFactory.getLogger(MemoryMessageRepository.class);

    private final Map<String, Message> messages = 
           new ConcurrentHashMap<String, Message>();

    @Cacheable("message")
    public Message getMessage(String title){
        LOG.info("Fetching message");
        return messages.get(title);
    }
    @CacheEvict(value="message", key="message.title")
    public void save(Message message){
        LOG.info("Saving message");
        messages.put(message.getTitle(), message);
    }
    public Collection<Message> findAll() {
        return messages.values();
    }
    
    @PostConstruct
    public void addSomeDefaultMessages(){
        save(new Message("Hello", "Hello World"));
        save(new Message("Appointment", "Remember the milk!"));
    }
    
}

Here you’ll notice that the finder method has a @Cachable annotation on it with a name that specifies the cache to store to. It can also use additional attributes, for example a key which uses an expression language to determine a key from the arguments that are passed in. The default is the value of all the method arguments. On the save method I use @CacheEvict to remove the cached element from the cache if it already exists.

This of course won’t work on it’s own, so you’ll have to enable it yourself (which is good… the last thing you need is to discover a production app caching things it shouldn’t be caching). Sadly as of the time of this writing I haven’t discovered how to do this in non-xml, so here is the spring xml file to enable it and use ehcache as the implementation.

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:cache="http://www.springframework.org/schema/cache"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
  <cache:annotation-driven />
  
        <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
        <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" 
                p:config-location="classpath:com/jamescarr/example/ehcache.xml"/>
 </beans>

The ehcache configuration:

<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <cache name="message"
       maxElementsInMemory="100"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"/>
    
</ehcache>

And finally adding this to the AppConfiguration, which includes doing a simple @ImportResource.

package com.jamescarr.configuration;
import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

import com.jamescarr.example.MessagePrinter;

@Configuration
@ComponentScan("com.jamescarr.example")
@ImportResource("classpath:com/jamescarr/example/cache-context.xml")
public class AppConfig {
        @Autowired
        private MessagePrinter messagePrinter;
        @PostConstruct
        public void doSomething(){
                messagePrinter.printMessage("Hello");
                messagePrinter.printMessage("Hello");
                
        }
        public static void main(String[] args) {
                new AnnotationConfigApplicationContext(AppConfig.class);
        }
}

When running this example there should be a log message for the first time the method is hit, then it is not seen the second time (since it is being pulled from the cache. This is definitely pretty awesome for implementing Memoization for methods that might just have some CPU intensive computations (but give the exact expected results given a set of of inputs). I’m excited about doing some more work in this area… I’ve done method level caching before (it’s common) but it is awesome to be able to use it without having to DIY.

That’s it guys. A straightforward guide to get you started with Spring’s Cache Abstraction from James Carr. Don’t forget to share!

Related Articles:

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

One Response to "Spring 3.1 Cache Abstraction Tutorial"

Leave a Reply


× five = 35



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close