Spring 3.0 and @Cacheable with a Warning!

Many systems (and developers, myself included) have come to rely heavily on the Spring method caching provided by the (now deprecated) spring-modules-cache (https://springmodules.dev.java.net/docs/reference/0.8/html/cache.html) add-on, providing an annotation-driven integration of various caching-frameworks (including ehcache) through the @Cacheable annotation.

Recently, I was involved in upgrading a large Spring-driven website from Spring 2.5 to Spring 3.0. During this we discovered that the method-caching support that was delivered through spring-modules-cache add-on (which we rely heavily on throughout our system) is not compatible with Spring 3. The new “Spring Extensions” (http://www.springsource.org/extensions/list) inititive from springsource have yet to include a replacement for this module. In the meantime, alternatives are available.

We ended up using the spring-ehcache-annotations projekt hosted at googlecode (http://code.google.com/p/ehcache-spring-annotations/ especially http://code.google.com/p/ehcache-spring-annotations/wiki/SwitchingFromSpringModules). The refactoring required was limited to changing the package include of the @Cacheable annotation and the cacheName attribute which the implementors of the project for some reason decided to have different than the spring-modules version.

However – and here comes the warning – while this seemed to work without any problems during testing, once in production we started noticing inconsistent behaviour of our system. Finally we managed to home in on the root-cause which turned out to be this new caching integration. As it turned out, we found serious flaws in the cache key generators in spring-ehcache-annotations. In the version we use (1.1.2), after some testing, we found that for methods with multiple parameters, we could get the default generator to produce identical keys for different combinations of input values. This is obviously a serious showstopper. The whole point of method-caching is to maintain unique cache records for each distinct combination of input values of your decorated methods. We ended up manually including the default cache-key generator from the old spring-modules-cache project and instructing spring-ehcache-annotations to use that instead. The following classes were required to include:

  • org.springmodules.cache.key.HashCodeCacheKeyGenerator
  • org.springmodules.cache.key.HashCodeCacheKey
  • org.springmodules.cache.key.HashCodeCalculator
  • org.springmodules.cache.util.Reflections
  • org.springmodules.util.Objects

NOTE: the HashCodeKeyGenerator has to be modified to implement com.googlecode.ehcache.annotations.key.CacheKeyGenerator instead of org.springmodules.cache.key.CacheKeyGenerator

In your spring-config, define bean for the “old” key generator

<!-- spring modules cache key generator -->
<bean name="springModulesHashCodeCacheKeyGenerator" class="org.springmodules.cache.key.HashCodeCacheKeyGenerator"/>

Then go ahead and override the default key generator in your spring config

<ehcache:annotation-driven default-cache-key-generator="springModulesHashCodeCacheKeyGenerator"/>