David is a systems architect who has been developing software professionally since 1991. He started programming in Java way back with Java 1.0 developing desktop applications and applets. Since 2001 he has been developing enterprise applications using both Java standards and open source solutions. David is the author of "Building SOA-Based Composite Applications using NetBeans 6" and "Seam 2.x Web Development". David is a DZone MVB and is not an employee of DZone and has posted 22 posts at DZone. You can read more from them at their website. View Full User Profile

Spring 3.1.M1 @Cacheable Doesn’t Evict – A Workaround

05.12.2011
| 7976 views |
  • submit to reddit

Spring 3.1 introduces a new feature to allow methods to be cached and evicted thus allowing resource heavy methods to be avoided where possible. Caching is enabled via the new @Cacheable and @CacheEvict annotations. For full details of Spring caching have a look at Costin Leau’s blog post.

One example of caching would be, for example, database activity. We can apply the @Cacheable annotation to a find operation and then apply the @CacheEvict to an update / delete operation.  In this sense, caching would work much like a second level cache in Hibernate or JPA.

To enable caching on a find method, the method needs to be annotated with the @Cacheable annotation identifying which cache to use.  Spring allows multiple caches to be defined each of which can be backed by a different caching abstraction.

@Cacheable("items")
public Item find(long itemId) {
Item item = entityManager.find(Item.class, itemId);
return item;
}

When it is time to invoke the find method, Spring checks in the specified cache to see if the results of the operation have already been cached and if the results can be therefore be returned from cache instead of invoking the method. Spring uses the method arguments as the key, so in this case the itemId parameter.

To evict an entry from the cache when an object is updated in the database, the @CacheEvict annotation can be used.  Again, this annotation takes a parameter identifying which cache to use.

@CacheEvict(value = "items", key = "#item.id")
public void updateItem(Item item) {
entityManager.merge(item);
}

You can see in this sample code, that Spring Expression Language has been used to define the key for items in the cache.  This is necessary as a long is not being used as the key as in the previous example so cache entries would not be found.

This all looks pretty straightforward, but unfortunately due to bug SPR-8015 it does not work.

To quote the bug report:

“… it's not working because the DefaultKeyGenerator simply hashes the given parameters as is. In case no key attribute is configured (just like in the above example) the parameters will be handed in as single-element-Object[] causing a different hash to be created than if the single object would be handed to the key generator directly”

This is fixed in Spring 3.1.M2, but in the meantime, can be worked around by explicitly specifying the key on the @Cacheable annotation, i.e.

@Cacheable(value = "items", key = "#itemId")
public Item find(long itemId) {
Item item = entityManager.find(Item.class, itemId);
return item;
}

From http://www.davidsalter.co.uk/1/post/2011/05/spring-31m1-cacheable-doesnt-evict-a-workaround.html

Published at DZone with permission of David Salter, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

David Martin replied on Fri, 2011/05/13 - 4:24am

On the other hand, we are talking about a milestone version of the upcoming 3.1.

If you need such a mechanism, maybe you can have a look at this project (http://code.google.com/p/ehcache-spring-annotations/), coming from the old Spring Modules portfolio.

David Salter replied on Sat, 2011/05/14 - 4:07am in response to: David Martin

Hi David, This was tested against a milestone release of Spring and is fixed in the next milestone.  For the moment though, its a good workaround.

Thanks for the link btw.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.