Caching in Spring Example + Ehcache + Cacheable + Annotation/JavaConfig

By Dhiraj Ray, 25 November,2016  

As we know EhCache is a widely used caching library. Spring provides easy annotation based integration mechanism of ehcache using @Cacheable. Here we will be creating a sample example to integrate Ehcache with spring by using @Cacheable annotation.We will be caching user details and try to fetch the same user detail again and again and compare the time required to fetch it. The spring configuration here in the app will be completely java config.

Environment Setup

1. JDK 8 2. Spring 4 3. Intellij Idea/ eclipse 4. Maven

Project Structure

spring-ehcache-project-structure

Maven Dependencies

Following are the maven dependencies required for spring ehcache implementation.

pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.developerstack</groupId> <artifactId>spring-caching-example</artifactId> <version>0.1.0</version> <properties> <spring.version>4.1.0.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml$gt </configuration> </plugin> </plugins> </build> </project>

Spring Bean Configuration

Now let us configure our beans.

@EnableCaching : Enables Spring's annotation-driven cache management capability. If no config location is specified, a CacheManager will be configured from "ehcache.xml" in the root of the class path (that is, default EhCache initialization - as defined in the EhCache docs - will apply).

CacheManager : Allows for retrieving named Cache regions.

BeanConfig.java
package com.developerstack.config; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.ehcache.EhCacheCacheManager; import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @Configuration @EnableCaching @ComponentScan(basePackages = "com.developerstack") public class BeanConfig { @Bean public CacheManager cacheManager() { return new EhCacheCacheManager(ehCacheCacheManager().getObject()); } @Bean public EhCacheManagerFactoryBean ehCacheCacheManager() { EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean(); cmfb.setConfigLocation(new ClassPathResource("ehcache.xml")); cmfb.setShared(true); return cmfb; } }

Following is the model class to hold user details.

UserDetails.java
package com.developerstack.model; public class UserDetails { private int id; private String firstName; private String lastName; private String email; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }

Let us define our service. Here we are caching the userDetails object. The value user is the same as we defined have defined in our ehcache.xml.

UserServiceImpl.java
package com.developerstack.service.impl; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.developerstack.model.UserDetails; import com.developerstack.service.UserService; @Service("userService") public class UserServiceImpl implements UserService { @Cacheable(value="user", key="#id") public UserDetails findUser(long id) { pause(3000L); UserDetails ud1 = new UserDetails(); ud1.setId(id); ud1.setEmail("john@example.com"); ud1.setFirstName("John"); ud1.setLastName("Doe"); return ud1; } private void pause(long sec) { try { Thread.sleep(sec); } catch (InterruptedException e) { e.printStackTrace(); } } }

Below is the ehcache.xml. This file has the cache configuration.

ehcache.xml
<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="user" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <persistence strategy="localTempSwap" /> </cache> </ehcache>

Now let us create Application.java which will execute the service to test whether our caching implementation is working as expected or not. Here we will be calling the same method of the service class with same and different parameters and analyse the time required to execute the methods. based on this we will draw our conclusion on the behaviour of caching.

Application.java
package com.developerstack.config; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.developerstack.service.UserService; public class Application { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); UserService obj = context.getBean("userService", UserService.class); long initialMillis = System.currentTimeMillis(); obj.findUser(1L); long currentMillis = System.currentTimeMillis(); System.out.println("Time taken to fetch user for first time " + (currentMillis - initialMillis)/1000 + " sec"); System.out.println(); System.out.println("*************finding user for second time ****************************"); initialMillis = System.currentTimeMillis(); obj.findUser(1L); currentMillis = System.currentTimeMillis(); System.out.println("Time taken to fetch same user again " + (currentMillis - initialMillis)/1000 + " sec"); System.out.println(); System.out.println("*************finding new user ****************************"); initialMillis = System.currentTimeMillis(); obj.findUser(2L); currentMillis = System.currentTimeMillis(); System.out.println("Time taken to fetch another user " + (currentMillis - initialMillis)/1000 + " sec"); ((ConfigurableApplicationContext) context).close(); } }

Run Application

1. Run Application.java as a java application. And analyse the console output. For the first time, the method took 3 seconds to find and return the user object. At this point the output is cached with key id. When we again tried to find user with same id, the method did not execute and the user object was returned from cache and hence it took 0 sec to find the user. Next, we again invoked the method with different id, but this time since the user with id 2 is not cached, the mmethod executed and tok 3 seconds to find and return the user object.

spring-ehcache-example

Conclusion

I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Download the source

References

Spring Framework References

Spring Boot References

Hibernate Docs

Suggest more topics in suggestion section or write your own article and share with your colleagues.

Is this page helpful to you? Please give us your feedback below. We would love to hear your thoughts on these articles, it will help us improve further our learning process.

Further Reading: