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
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.javapackage 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; } }
Other Interesting Posts Spring 5 Features and Enhancements Spring Hibernate Integration with complete JavaConfig Spring MVC Angularjs Integration with complete JavaConfig Spring Boot Spring MVC Example Spring Boot Thymeleaf Example Spring Boot Security Redirect after Login with complete JavaConfig Spring Security Hibernate Example with complete JavaConfig Securing REST API with Spring Security Basic Authentication Spring Security Password Encoding using Bcrypt Encoder Spring Boot Security Custom Form Login Example Spring JMS Activemq Integration with Spring Boot Websocket spring Boot Integration without STOMP with complete JavaConfig Spring Junit Integration with complete JavaConfig Spring Ehcache Cacheable Example with complete javaConfig
Following is the model class to hold user details.
UserDetails.javapackage 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.javapackage 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.javapackage 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.
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.