Spring 3.1 Caching and @CacheEvict

My last blog demonstrated the application of Spring 3.1’s @Cacheable annotation that’s used to mark methods whose return values will be stored in a cache. However, @Cacheable is only one of a pair of annotations that the Guys at Spring have devised for caching, the other being @CacheEvict.

Like @Cacheable@CacheEvict has valuekey and condition attributes. These work in exactly the same way as those supported by @Cacheable, so for more information on them see my previous blog: Spring 3.1 Caching and @Cacheable.

CacheEvict supports two additional attributes: allEntries and beforeInvocation. If I were a gambling man I’d put money on the most popular of these being allEntriesallEntries is used to completely clear the contents of a cache defined by @CacheEvict‘s mandatory value argument. The method below demonstrates how to apply allEntries:

  @CacheEvict(value = "employee", allEntries = true)
  public void resetAllEntries() {
    // Intentionally blank
  }

resetAllEntries() sets @CacheEvict’s allEntries attribute to “true” and, assuming that thefindEmployee(...) method looks like this:

  @Cacheable(value = "employee")
  public Person findEmployee(String firstName, String surname, int age) {

    return new Person(firstName, surname, age);
  }

…then in the following code, resetAllEntries(), will clear the “employees” cache. This means that in the JUnit test below employee1 will not reference the same object as employee2:

  @Test
  public void testCacheResetOfAllEntries() {

    Person employee1 = instance.findEmployee("John", "Smith", 22);
    instance.resetAllEntries();
    Person employee2 = instance.findEmployee("John", "Smith", 22);

    assertNotSame(employee1, employee2);
  }

The second attribute is beforeInvocation. This determines whether or not a data item(s) is cleared from the cache before or after your method is invoked.

The code below is pretty nonsensical; however, it does demonstrate that you can apply both @CacheEvict and @Cacheable simultaneously to a method.

  @CacheEvict(value = "employee", beforeInvocation = true)
  @Cacheable(value = "employee")
  public Person evictAndFindEmployee(String firstName, String surname, int age) {

    return new Person(firstName, surname, age);
  }

In the code above, @CacheEvict deletes any entries in the cache with a matching key before @Cacheable searches the cache. As @Cacheable won’t find any entries it’ll call my code storing the result in the cache. The subsequent call to my method will invoke @CacheEvict which will delete any appropriate entries with the result that in the JUnit test below the variable employee1 will never reference the same object asemployee2:

  @Test
  public void testBeforeInvocation() {

    Person employee1 = instance.evictAndFindEmployee("John", "Smith", 22);
    Person employee2 = instance.evictAndFindEmployee("John", "Smith", 22);

    assertNotSame(employee1, employee2);
  }

As I said above, evictAndFindEmployee(...) seems somewhat nonsensical as I’m applying both@Cacheable and @CacheEvict to the same method. But, it’s more that that, it makes the code unclear and breaks the Single Responsibility Principle; hence, I’d recommend creating separate cacheable and cache-evict methods. For example, if you have a cacheing method such as:

  @Cacheable(value = "employee", key = "#surname")
  public Person findEmployeeBySurname(String firstName, String surname, int age) {

    return new Person(firstName, surname, age);
  }

then, assuming you need finer cache control than a simple ‘clear-all’, you can easily define its counterpart:

  @CacheEvict(value = "employee", key = "#surname")
  public void resetOnSurname(String surname) {
    // Intentionally blank

  }

This is a simple blank marker method that uses the same SpEL expression that’s been applied to@Cacheable to evict all Person instances from the cache where the key matches the ‘surname’ argument.

  @Test
  public void testCacheResetOnSurname() {

    Person employee1 = instance.findEmployeeBySurname("John", "Smith", 22);
    instance.resetOnSurname("Smith");
    Person employee2 = instance.findEmployeeBySurname("John", "Smith", 22);
    assertNotSame(employee1, employee2);
  }

In the above code the first call to findEmployeeBySurname(...) creates a Person object, which Spring stores in the “employee” cache with a key defined as: “Smith”. The call to resetOnSurname(...) clears all entries from the “employee” cache with a surname of “Smith” and finally the second call tofindEmployeeBySurname(...) creates a new Person object, which Spring again stores in the “employee” cache with the key of “Smith”. Hence, the variables employee1, and employee2 do not reference the same object.

Having covered Spring’s caching annotations, the next piece of the puzzle is to look into setting up a practical cache: just how do you enable Spring caching and which caching implementation should you use? More on that later…

Happy coding and don’t forget to share!

Reference: Spring 3.1 Caching and @CacheEvict from our JCG partner Roger Hughes at the Captain Debug’s Blog blog.

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.

Leave a Reply


3 + three =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
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