• Menu
  • Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

JavaBeat

Java Tutorial Blog

  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)

Spring Cache Tutorial

September 15, 2015 //  by Krishna Srinivasan//  Leave a Comment

We have earlier written few interesting articles on caching in spring and another good article on @Cacheable and @CacheEvict annotations for caching in spring. This is another comprehensive tutorial for spring caching using Spring 4. Spring caching is available since 3.1, but spring 4.1 has added lot of cool features with the existing spring caching framework.  Another interesting part of this spring caching tutorial is that I am going to use Spring Boot for packaging and running this spring caching example.

Note that spring provides only the caching abstraction, the actual caching store is not implemented by spring caching framework. We have to configure some of the external caching storage.

Spring Cache Tutorial Table of Contents

Here is the list of topics covered in this tutorial about spring cache.

  1. What is Spring Cache?
  2. Cache Implementations
  3. Spring Cache Annotations
    1. @Cacheable
    2. @CachePut
    3. @CacheEvict
    4. @Caching
    5. @CacheConfig
  4. How to Enable Spring Cache?
  5. JCache (JSR – 107) Support
  6. EhCache Configuration
  7. Cache Fallback Mechanism
  8. Spring Boot Application
  9. Spring Cache Example Application
  10. Exceptions

What is Spring Cache?

  1. Spring’s core framework provides APIs for supporting caching in the existing spring applications.
  2. This support is available from Spring Framework 3.1 and there is significant improvement provided in the Spring 4.1.
  3. This is an abstract framework where Spring only provides the layer where other third party caching implementations can be easily plugged for storing data.
  4. In short, cache storage is not implemented by Spring, where as enabling and caching is supported by spring out of the box.
  5. Caching is supported for the methods and it works good if the methods return the same result for the given input for the multiple invocations.

Cache Implementations

As I have mentioned earlier, the actual implementations of the cache is by third party library and Spring provides only the abstract layer for enabling that specific cache implementation to store the cache data. Spring’s has the abstraction for the following list of cache implementations out of the box:

  1. JDK java.util.concurrent.ConcurrentMap based caches
  2. EhCache
  3. Gemfire Cache
  4. Guava Caches
  5. JSR 107 complaint caches

At the end of this tutorial, I will explain first two caches in the above list. For the ConcurrentMap we just need the Cache manager to be configured and the data stored in the in-memory, for the EhCache we have to add the ehcache.xml file in the classpath.

Spring Cache Annotations

The following are the list of spring caching annotations. These are specific to the spring framework, apart from that there are few more annotations that are implemented as part of the JCache (JSR – 107). I will explain that in the later part of this tutorial.

  1. @Cacheable
  2. @CacheEvict
  3. @CachePut
  4. @Caching
  5. @CacheConfig

@Cacheable

@Cacheable annotation is one of the most important and common annotation for caching the requests. If you annotate a method with @Cacheable, if multiple requests are received by the application, then this annotation will not execute the method multiple times, instead it will send the result from the cached storage.

Here is an example:

@Cacheable(value="users", condition="#name.length < 32", unless="#result.hardback")
	public UserDetails findById(String id) {
		slowResponsee();
		return new UserDetails(id, "Name"+id);
	}

The following are the list of properties that can be used inside @Cacheable annotation to customize the caching functionality.

Attributes Description
cacheManager The bean name of the cache manager
cacheNames

The list of cache store names where the method

cache has to be stored. This should be any array of strings.

cacheResolver The name of the custom cache resolver
condition

This is Spring Expression Language (SPeL) for the conditional caching

for the method

key Spring Expression Language for computing the key dynamically
keyGenerator The bean name of the custom key generator to use
unless Spring Expression Language for bypassing caching for specific scenarios.
value It is a cache name to store the caches

@CachePut

@CachePut annotation helps for updating the cache with the latest execution without stopping the method execution. The only difference between @Cacheable and @CachePut is that first one is only once executed for the combination of similar key and updated the cache storage and later is executed every time and updates the cache storage.

It is not recommended to use both the annotation for the same method which will result in an unexpected results. It is highly recommended to use either @Cacheable or @CachePut for a method.

The list of attributes defined in this annotation is similar to the @Cacheable.

@CacheEvict

@CacheEvict annotation is used for removing a single cache or clearing the entire cache from the cache storage. This annotation supports suitable parameters to execute the condition to clear the matching set of cached from the store. If you set the allEntries=true , then the entire cache will be cleared.

The list of attributes supported in this annotation is shown below:

Attributes Description
allEntries It indicated whether all the data in the cache has to be removed
beforeInvocation This attribute indicates whether the eviction has to be done before the method invocation.
cacheManager The bean name of the cache manager
cacheNames

The list of cache store names where the method

cache has to be stored. This should be any array of strings.

cacheResolver The name of the custom cache resolver
condition

This is Spring Expression Language (SPeL) for the conditional caching

for the method

key Spring Expression Language for computing the key dynamically
keyGenerator The bean name of the custom key generator to use
unless Spring Expression Language for bypassing caching for specific scenarios.
value It is a cache name to store the caches

 @Caching

@Caching annotation used for grouping multiple annotations of the same type together when one annotation is not sufficient for the specifying the suitable condition. For example, you can put mutiple @CacheEvict ot @CachePut annotation inside @Caching to narrow down your conditions as you need.

The list of attributes supported in this annotation is shown below:

Attributes Description
cacheable This is array of @Cacheable annotation
evict This is array of @CacheEvict annotation
put This is array of @CachePut annotation

@CacheConfig

If you have multiple operations in a class where each operation has to be given cache configuration details, this could be tedious job if the number of operations are higher. You can annotate @CacheConfig at the class level to avoid repeated mentioning in each method. For example, in the class level you can provide the cache name and in the method you just annotate with @Cacheable annotation.

The list of attributes supported in this annotation is shown below:

Attributes Description
cacheManager The bean name of the cache manager
cacheNames

The list of cache store names where the method

cache has to be stored. This should be any array of strings.

cacheResolver The name of the custom cache resolver
keyGenerator The bean name of the custom key generator to use

Enable Spring Caching

If you are enabling enabling caching in your spring applications, then you have to take care of the following two things:

  1. Caching declaration – Identify the methods that has to be cached and define the caching policy.
  2. Cache Configurations – Configure the cache manager where the backing data is stored and retrieved for the quick response.
  3. EnableCaching – Finally you have to enable the caching using Java configurations or the XML configurations.

Caching in spring is not enabled by default. We have to enable the caching by annotating a configuration class with @EnableCaching or declaring it in the XML file. Here is the example snippet for enabling the caching.

@EnableCaching
public class Application {

If you are using XML configurations, then it looks like this:

<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" 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 />

</beans>

The advantage of having the control to enable or disable is that we are not required to update the configurations in every single file. We just have to remove the configuration in single place, rest all will work fine.

JCache (JSR – 107) Support

Since spring framework 4.1, spring’s caching abstraction completely supports the JCache specification and you can use JCache annotations without any special configurations. Here is the table that compares the list of annotations in Spring and JCache specification.

Spring JCache (JSR-107) Remarks
@Cacheable @CacheResult
@CachePut @CachePut  There is no change in the annotation name
@CacheEvict @CacheRemove  @CacheRemove evicts conditionaly when

there is exception throw from the method.

@CacheEvict(allEntries=true) @CacheRemoveAll  JCache adds another annotation for

removing all the cache entries

@CacheConfig @CacheDefaults  Both the annotations work similar

The JCache is located under the package org.springframework.cache.jcache. You can declare the JCache as like this:

<bean id="cacheManager" class="org.springframework.cache.jcache.JCacheCacheManager" p:cache-manager-ref="jCacheManager"/>

<!-- JSR-107 cache manager setup -->
<bean id="jCacheManager" .../>

If you are using Java based configuration, please add the below lines of code to your configuration class:

@Bean
public CacheManager jCacheManager() {
   return new JCacheCacheManager();
}

EhCache Configuration

Ehcache is one of the most popular caching implementation available as the open source caching implementation. This is located under the ackage org.springframework.cache.ehcache. You have to declare appropriate cache manager to start using it in your application.

The cache manager configuration for ehcache is:

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>

<!-- EhCache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>

If you want to configure using the Java configuration class, add the following lines of code:

@Bean
	public CacheManager ehCacheManager() {
		return new EhCacheCacheManager(ehCacheCacheManager().getObject());
	}
	@Bean
	public EhCacheManagerFactoryBean ehCacheCacheManager() {
		EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
		cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
		cmfb.setShared(true);
		return cmfb;
	}

Note that you should have ehcache.xml in the classpath or any other location where your spring application can load without any issues. This configuration provides more details about the cache size, file name, etc.

Here is the example of the ehcache.xml file:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true">

	<diskStore path="java.io.tmpdir" />
	
	<cache name="movieFindCache" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" transactionalMode="off">
		<persistence strategy="localTempSwap" />
	</cache>

</ehcache>

You can read more about configuring the ehcahce here.

Cache Fallback Mechanism

There are situations when we change to different environments or any other scenarios our applications may not have caching store configured. In this case a runtime exception will be thrown by the spring application due to failure on finding the suitable cache store. Instead of removing the caching declarations in the application (which is teadious and time consuming work), we can configure a fall bacl dummy cache store to avoid and exception thrown. What happens is, when there is no cache store found by the spring application, it just executes the method normally without enforcing any caching mechanism. The declaration for fall back cache would look like this:

<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
    <property name="cacheManagers">
        <list>
            <ref bean="jdkCache"/>
            <ref bean="ehCache"/>
        </list>
    </property>
    <property name="fallbackToNoOpCache" value="true"/>
</bean>

Spring Boot Application

We are going to run this application using Spring Boot command liner. This is very easy and simple way to quickly run our examples. I am using Spring Boot 1.2.5 for running this example. Here is the pom.xml required to download the dependencies:

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.2.5.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
			<version>2.9.0</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
	</dependencies>

Application.java

@Configuration
@SpringBootApplication
@EnableCaching
public class Application {
	private static final Logger log = LoggerFactory.getLogger(Application.class);

	@Component
	static class Runner implements CommandLineRunner {
		@Autowired
		private UserRepository userRepository;

		public void run(String... args) throws Exception {
			log.info(".... Fetching user details");
			log.info("User 001 -->" + userRepository.findById("001"));
			log.info("User 001 -->" + userRepository.findById("001"));
			log.info("User 001 -->" + userRepository.findById("001"));
			log.info("User 002 -->" + userRepository.findById("002"));
			log.info("User 002 -->" + userRepository.findById("002"));
			log.info("User 002 -->" + userRepository.findById("002"));
		}
	}
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
	
	//JDK Cache Manager
	@Primary
	@Bean
	public CacheManager jdkCacheManager() {
		return new ConcurrentMapCacheManager("users");
	}
	// EhCache Manager
	@Bean
	public CacheManager ehCacheManager() {
		return new EhCacheCacheManager(ehCacheCacheManager().getObject());
	}
	
	//JSR 107 - JCache Manager
	@Bean
	public CacheManager jCacheManager() {
		return new JCacheCacheManager();
	}
	
	//Guava Cache Manager
//	@Bean
//	public CacheManager guavaCacheManager() {
//		return new GuavaCacheManager();
//	}

	@Bean
	public EhCacheManagerFactoryBean ehCacheCacheManager() {
		EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
		cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
		cmfb.setShared(true);
		return cmfb;
	}
}

Spring Boot Auto Configuration Support

Update: After the release of Spring Boot 1.3.0

When I am writing this article, Spring Boot 1.2.5 doesn’t support the auto-configuration for caching technologies. We have to manually add the required dependencies to the pom.xml file. Since the Spring Boot 1.3.0 release, new starter pom spring-boot-starter-cache has been added to support the auto-configuration of caching technologies available in the classpath.

If you are using the spring boot 1.3.0 or later versions, you have to follow these steps to enable the caching configurations:

  • Just add the spring-boot-starter-cache and caching implementation JAR file to the pom.xml file
  • Annotate with @EnableCaching in the @Configuration file
  • It is not required to add the caching manager beans in the @Configuration file. Spring boot will add the required beans based on the caching technology available in the classpath.

The following are list of caching technologies supported as of now. If you are using any one of these technologies, then spring boot can perform the auto-configuration for you:

  • EhCache
  • Hazelcast
  • Infinispan
  • Any JCache (JSR 107) implementation
  • Redis
  • Guava
  • Simple Map based in-memory cache also supported in the auto configuration

Spring Cache Example Application

This tutorial uses a simple example to illustrate the functionality of the caching in spring framework. And also it uses the ConcurrentMapCacheManager as the cache manager. This is a simple cache manager available with the Java release.

This example adds the EhCache, Guava, ConcurrentMapCacheManager and JCache managers in the Java configuration class. These configurations are added as part of the Spring Boot’s startup class with @Configuration annotation.

This example is to get the user details by running the sleep mode in the method where @Cacheable annotation is used. When you run the example, you can clearly note the difference for the first time and the subsequent invocations.

Following are the list of files that are part of this example application:

  • Application.java
  • UserDetails.java
  • UserRepository.java
  • UserRepositoryImpl.java
  • ehcache.xml
  • pom.xml

You can download the spring caching example application.

Icon

Spring Caching Example Application

1 file(s) 5.89 KB
Download

Exceptions

This section shows some of the common error or exceptions that are encountered while developing this application. If you see any other issues, please write it in the comments section.

CacheManager Registration Problem: The below exception will be thrown when you have enabled caching functionality and not configured any of the cache manager. You should have atleast one cache manager to store the incoming catches.

Exception in thread "main" java.lang.IllegalStateException: No CacheResolver specified, and no bean of type CacheManager found. Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.
	at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:189)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)	

Cache Manager Name Problem: When you are not specifying the cache name in the cache manager and you are trying to use it in the @Cacheable annotation. For example look at the following entry:

@Cacheable(value="users1")
	public UserDetails findById(String id) {
		slowResponsee();
		return new UserDetails(id, "Name"+id);
	}

In the above code, it tries to search for the cache manager with the name of “users”, if it is not finding then it will throw the below exception.

Caused by: java.lang.IllegalArgumentException: Cannot find cache named 'users1' for CacheableOperation[public net.javabeat.spring.cache.UserDetails net.javabeat.spring.cache.UserRepositoryImpl.findById(java.lang.String)] caches=[users1] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless=''
	at org.springframework.cache.interceptor.AbstractCacheResolver.resolveCaches(AbstractCacheResolver.java:81)
	at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:214)

Primary or Declare a Specific CacheManager Exception

In the above code, we have declaraed JDK cache and EhCache for our applications. But, if the application could not find any of these stores, then we have configured fallbackToNoOpCache to execute methods without any exceptions thrown at runtime.

When you are declaring more than one cache managers in your application, your application may not be able to resolve which cache manager has to be used for the annotation not using the cacheManager attribute to specify the cache manager name. In that case, you would encounter the following exception.

java.lang.IllegalStateException: No CacheResolver specified, and no unique bean of type CacheManager found. Mark one as primary or declare a specific CacheManager to use.
	at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:185)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)

The above problem can be resolved by making one of the cache manager as the primary by annotating as @Primary as below:

@Primary
	@Bean
	public CacheManager jdkCacheManager() {
		return new ConcurrentMapCacheManager("users");
	}

Category: Spring FrameworkTag: Spring Cache

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Previous Post: « NodeJS : ExpressJS Session Management
Next Post: ExpressJS Session Store using MongoDB, PostgreSQL »

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Follow Us

  • Facebook
  • Pinterest

FEATURED TUTORIALS

New Features in Spring Boot 1.4

Difference Between @RequestParam and @PathVariable in Spring MVC

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Introductiion to Jakarta Struts

What’s new in Struts 2.0? – Struts 2.0 Framework

JavaBeat

Copyright © by JavaBeat · All rights reserved
Privacy Policy | Contact