Using Spring @Cacheable annotations

Table of Contents

Today I needed some performance improvements on a application that makes quite a few calls to a database. My default statement is not to implement performance improvements unless there is a issue. Well it just happened.

I did not wanted to change any of the existing code so what to do. In Spring 3.x the added a caching mechanism. Implementing this is simple:

@Configuration 
@EnableCaching 
public class SpringConfiguration { 
 
 /** 
 * Name of the available Cache 
 */ 
 public final static String CORE_CACHE = "default"; 
 
 /** 
  * Creates a in memory cache using a concurrent HasMap. 
  * 
  * @return cache manager 
  */ 
  @Bean 
  public CacheManager cacheManager() { 
    return new ConcurrentMapCacheManager(CORE_CACHE);
  } 
  
  @Component 
  public class MyDataImpl implements MyData { 
    
    @PersistenceContext(unitName = "persistenceUnit") 
    private EntityManager entityManager; 
    
    @Cacheable(value = SpringConfiguration.CORE_CACHE) 
    @Override 
    public Map<String, Code> getCodes() {
      final TypedQuery<Map<String, CodeTypes>> codesQuery 
        = entityManager.createNamedQuery(CODE_QUERY, 
          Map<String, CodeTypes>); 
      
      return codesQuery.getResultList(); 
  }
}
//some code is omitted

My assumption was with this in place i got a working caching mechanism. Unfortunately it is not the case.

The spring implementation of Spring assumes that there is at least a key. When there is no argument available this becomes the String value “0″. In my application I had multiple functions that collected data from a DB but are without a specific key. (And yes I could have done this differently, for example with @PostConstruct annotation, but that is besides the point).
Bot how to solve this? The documentation does not describe that it does this.

The answer is right there in the documentation:  Spring Expression language (SpEL).
By means of the SpEL you can use for example the method name to use as a key of the cached value.

With this the annotated method becomes:

@Component 
public class MyDataImpl implements MyData { 
 
 @PersistenceContext(unitName = "persistenceUnit")
 private EntityManager entityManager; 
 
 @Cacheable(value = SpringConfiguration.CORE_CACHE, 
            key = "#root.method.name") 
 @Override public Map<String, Code> getCodes() {
   final TypedQuery<Map<String, CodeTypes>> 
     codesQuery = 
       entityManager.createNamedQuery(CODE_QUERY, 
           Map<String, CodeTypes>); 
           
    return codesQuery.getResultList(); 
  }
}

With this annotation the cached element is stored in the map with the method name as the key.

Share :

Related Posts

Builder pattern with annotations

I Think every body should know their patterns. the GoF created that book a long time ago but still not every body knows them by heart?

Read More

is package-private the new private?

Just a few days ago I attended the DEVOXX conference in Belgium. The last session I attended was from Adam Bien’s session Real World Java EE.

Read More

Builder pattern with annotations (Part 2)

It took me some time to get all for the annotation builder into central but it’s there. see previous article for details on usage

Read More