Spring 4 provides seamless JCache integration. In this example, I am using EhCache as JCache specification provider.

JCache is JSR 107 specification that provides annotations support such as @CacheResult, @CachePut, @CacheRemove and @CacheRemoveAll

@CacheResult

@CacheResult(cacheName = "person")
findPerson(@CacheKey String id)

By marking the method with the @CacheResult annotation, we tell the container that the findPerson method is backed by the cache entry person. That is each time the method is called, a cache lookup is performed using as key the method parameters (in this case the id argument). If a value is found, it will be returned and the method execution skipped. However, if the key is not found, the method is executed as usual and its result stored in the cache so the next time the method is invoked, the result can be returned without actually executing the (expensive or slow) method.

@CachePut

@CachePut
public Person savePerson(@CacheKey String id, @CacheValue Person person)

The parameter annotated with @CacheValue is required for @CachePut.

@CacheRemove and @CacheRemoveAll

@CacheRemove
public void removePerson(Person person)
@CacheRemoveAll
public void removeAllPersons()

You can evict either one cache object at a time or all cache objects at once.

For more information you can read https://spring.io/blog/2014/04/14/cache-abstraction-jcache-jsr-107-annotations-support

Now I will show you an example on JCache using EhCache implementation here.

Prerequisites

The following configurations are required in order to run the application

Eclipse Kepler
JDK 1.8
Tomcat 8
Have maven 3 installed and configured
Spring 4 and ehcache-core, jcache, cache-api dependencies in pom.xml

Step 1. Create a maven based web project in Eclipse

Go to File -> New -> Other. On popup window under Maven select Maven Project. Then click on Next. Select the workspace location – either default or browse the location. Click on Next. Now in next window select the row as highlighted from the below list of archtypes and click on Next button.

maven-arctype-quickstart

Now enter the required fields (Group Id, Artifact Id) as shown below

Group Id : com.roytuts
Artifact Id : spring-jcache

Step 2. Modify the pom.xml file as shown below.

<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.roytuts</groupId>
	<artifactId>spring-jcache</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>spring-jcache</name>
	<url>http://maven.apache.org</url>

	<repositories>
		<repository>
			<id>terracotta-releases</id>
			<url>http://www.terracotta.org/download/reflector/releases</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
		<spring.version>4.3.5.RELEASE</spring.version>
		<ehcache.version>2.9.0</ehcache.version>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.0.RELEASE</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>javax.cache</groupId>
			<artifactId>cache-api</artifactId>
		</dependency>
		<!-- ehcache jars along with its jsr107 impl -->
		<dependency>
			<groupId>org.ehcache</groupId>
			<artifactId>jcache</artifactId>
			<version>1.0.0</version>
		</dependency>
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache-ee</artifactId>
			<version>${ehcache.version}</version>
		</dependency>
		<!-- spring for jsr107 annotation support -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Step 3. If you see JRE System Library[J2SE-1.5] then change the version by below process

Do right-click on the project and go to Build -> Configure build path, under Libraries tab click on JRE System Library[J2SE-1.5], click on Edit button and select the appropriate jdk 1.8 from the next window. Click on Finish then Ok.

Change also the Compiler compliance level as 1.8 from Java -> Compiler.

Step 4. Create ehcache.xml file put under src/main/resources

<?xml version="1.0" encoding="UTF-8"?>
<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="person" maxEntriesLocalHeap="10000"
		maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="20"
		timeToIdleSeconds="300" timeToLiveSeconds="600"
		memoryStoreEvictionPolicy="LFU" transactionalMode="off">
		<persistence strategy="localTempSwap" />
	</cache>

</ehcache>

Step 5. Create below Person model class

package com.roytuts.jcache.model;

import java.io.Serializable;

public class Person implements Serializable {

	private static final long serialVersionUID = 1169068499334259093L;

	private String id;
	private String name;

	public Person(String id, String name) {
		this.id = id;
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + "]";
	}

}

Step 6. Create below PersonRepository class

package com.roytuts.jcache.repository;

import com.roytuts.jcache.model.Person;

public interface PersonRepository {

	Person findPerson(String id);

	Person savePerson(String id, Person person);

	void removePerson(Person person);

	void removeAllPersons();

}

Step 7. Create below PersonRepositoryImpl class

package com.roytuts.jcache;

import javax.annotation.PostConstruct;
import javax.cache.annotation.CacheDefaults;
import javax.cache.annotation.CacheKey;
import javax.cache.annotation.CachePut;
import javax.cache.annotation.CacheRemove;
import javax.cache.annotation.CacheRemoveAll;
import javax.cache.annotation.CacheResult;
import javax.cache.annotation.CacheValue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.stereotype.Repository;

import com.roytuts.jcache.model.Person;
import com.roytuts.jcache.repository.PersonRepository;

@Repository
@EnableCaching
@CacheDefaults(cacheName = "person")
@CacheConfig(cacheNames = "person")
public class PersonRepositoryImpl implements PersonRepository {

	@Autowired
	private CacheManager cacheManager;

	private Cache cache;

	private static String[] names = new String[] { "Younker Patel", "Zollicoffer Robinson", "Zeh Haugen",
			"Yager Johansen", "Zickefoose Macdonald", "Yerkes Karlsson", "Yerby Gustavsson", "Zimple Svensson",
			"Youmans Stewart", "Zahn Davis", "Zenz Davis", "Zamastil Jackson", "Zamastil Gustavsson", "Zucchero Walker",
			"Zielke Martin", "Zabowski Carlsson", "Yoes Hansson", "Zuczek Smith", "Zeidler Watson", "Yingling Harris",
			"Zahn Karlsen", "Zimmermann Olsson", "Zerkey Martin", "Zatovich Andersson", "Yurky Andersson",
			"Yeary Carlsson", "Yeary Olsen", "Zabowski Olsen", "Zuber Jackson", "Zeim Nilsen" };

	@PostConstruct
	public void init() {
		cache = cacheManager.getCache("person");

		int id = 1;
		for (String name : names) {
			cache.putIfAbsent(String.valueOf(id), new Person(String.valueOf(id), name));
			id++;
		}

	}

	@Override
	@CacheResult
	public Person findPerson(@CacheKey String id) {
		return (Person) cache.get(id);
	}

	@Override
	@CachePut
	public Person savePerson(@CacheKey String id, @CacheValue Person person) {
		return (Person) cache.putIfAbsent(id, person);
	}

	@Override
	@CacheRemove
	public void removePerson(Person person) {
		cache.evict(person.getId());
	}

	@Override
	@CacheRemoveAll
	public void removeAllPersons() {
		cache.clear();
	}

}

Step 8. Create below class CacheManagerProvider

package com.roytuts.jcache;

import org.ehcache.jcache.JCacheCachingProvider;
import org.ehcache.jcache.JCacheManager;
import org.springframework.cache.CacheManager;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CacheManagerProvider {

	@Bean
	public CacheManager cacheManager() {
		JCacheCacheManager cacheManager = new JCacheCacheManager();
		cacheManager.setCacheManager(new JCacheManager(new JCacheCachingProvider(), ehcache(), null, null));
		return cacheManager;
	}

	private net.sf.ehcache.CacheManager ehcache() {
		net.sf.ehcache.CacheManager cacheManager = new net.sf.ehcache.CacheManager();
		return cacheManager;
	}

}

Step 9. Create below Spring Boot main class

package com.roytuts.jcache.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;

import com.roytuts.jcache.model.Person;
import com.roytuts.jcache.repository.PersonRepository;

@EnableCaching
@SpringBootApplication
@ComponentScan(basePackages = "com.roytuts.jcache")
public class JCacheTest implements CommandLineRunner {

	private static final Logger LOGGER = LoggerFactory.getLogger(JCacheTest.class);

	@Autowired
	private PersonRepository personRepository;

	@Override
	public void run(String... args) throws Exception {
		LOGGER.info("Fetching Person details");

		Person person = personRepository.findPerson(String.valueOf(1));
		LOGGER.info("Cached Person Info: " + person);

		personRepository.savePerson("1000", new Person("1000", "Soumitra Roy"));
		LOGGER.info("Saved Person Info in cache: " + personRepository.findPerson("1000"));

		personRepository.removePerson(new Person("1000", "Soumitra Roy"));
		LOGGER.info("Has Person Info removed from cache: " + (personRepository.findPerson("1000") != null));

		personRepository.removeAllPersons();
		LOGGER.info("Is there still any Person Info in the cache: " + (personRepository.findPerson("1") != null));
	}

	public static void main(String[] args) {
		SpringApplication.run(JCacheTest.class, args);
	}

}

Step 10. Create below logback.xml file and put it under src/main/resources folder to override Spring Boot’s default logging mechanism

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<appender name="CA" class="ch.qos.logback.core.ConsoleAppender">
		<!-- Log message format -->
		<encoder>
			<pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
				%msg%n
			</pattern>
		</encoder>
	</appender>
	<appender name="RFA" class="ch.qos.logback.core.FileAppender">
		<file>SpringBoot.log</file>
		<encoder>
			<pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
			</pattern>
		</encoder>
	</appender>
	<root>
		<level value="INFO" />
		<appender-ref ref="CA" />
		<appender-ref ref="RFA" />
	</root>
</configuration>

Step 11. Now if you run the JCacheTest class then you will see below output in the Eclipse console and also a log file SpringBoot.log is created under the project’s root directory.

Console Output

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.0.RELEASE)

26-01-2017 18:22:24.936 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Starting JCacheTest on moni-pc with PID 2492 (D:\mars_workspace\jcache\target\classes started by moni in D:\mars_workspace\jcache)
26-01-2017 18:22:24.936 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				No active profile set, falling back to default profiles: default
26-01-2017 18:22:24.983 [main] INFO  o.s.c.a.AnnotationConfigApplicationContext -
				Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@b59d31: startup date [Thu Jan 26 18:22:24 IST 2017]; root of context hierarchy
26-01-2017 18:22:25.950 [main] WARN  n.s.e.config.CacheConfiguration -
				Configuration problem for cache person: MaxEntriesLocalHeap equal or greater than MaxEntriesLocalDisk. This will result in useless disk storage.
26-01-2017 18:22:25.950 [main] INFO  n.s.e.s.o.d.OffHeapDiskStoreFactory -
				Creating On Disk Area Using Config
 Explicit Disk Configuration:
Concurrency                : 16
Initial Segment Table Size : 64 slots
Segment Data Page Size     : 2KB

26-01-2017 18:22:26.232 [main] INFO  o.s.j.e.a.AnnotationMBeanExporter -
				Registering beans for JMX exposure on startup
26-01-2017 18:22:26.248 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Fetching Person details
26-01-2017 18:22:26.248 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Cached Person Info: Person [id=1, name=Younker Patel]
26-01-2017 18:22:26.263 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Saved Person Info in cache: Person [id=1000, name=Soumitra Roy]
26-01-2017 18:22:26.263 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Has Person Info removed from cache: false
26-01-2017 18:22:26.357 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Is there still any Person Info in the cache: false
26-01-2017 18:22:26.357 [main] INFO  com.roytuts.jcache.test.JCacheTest -
				Started JCacheTest in 1.703 seconds (JVM running for 2.609)

SpringBoot.log

26-01-2017 18:22:24.936 [main] INFO  com.roytuts.jcache.test.JCacheTest - Starting JCacheTest on moni-pc with PID 2492 (D:\mars_workspace\jcache\target\classes started by moni in D:\mars_workspace\jcache)
26-01-2017 18:22:24.936 [main] INFO  com.roytuts.jcache.test.JCacheTest - No active profile set, falling back to default profiles: default
26-01-2017 18:22:24.983 [main] INFO  o.s.c.a.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@b59d31: startup date [Thu Jan 26 18:22:24 IST 2017]; root of context hierarchy
26-01-2017 18:22:25.950 [main] WARN  n.s.e.config.CacheConfiguration - Configuration problem for cache person: MaxEntriesLocalHeap equal or greater than MaxEntriesLocalDisk. This will result in useless disk storage.
26-01-2017 18:22:25.950 [main] INFO  n.s.e.s.o.d.OffHeapDiskStoreFactory - Creating On Disk Area Using Config
 Explicit Disk Configuration:
Concurrency                : 16
Initial Segment Table Size : 64 slots
Segment Data Page Size     : 2KB

26-01-2017 18:22:26.232 [main] INFO  o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
26-01-2017 18:22:26.248 [main] INFO  com.roytuts.jcache.test.JCacheTest - Fetching Person details
26-01-2017 18:22:26.248 [main] INFO  com.roytuts.jcache.test.JCacheTest - Cached Person Info: Person [id=1, name=Younker Patel]
26-01-2017 18:22:26.263 [main] INFO  com.roytuts.jcache.test.JCacheTest - Saved Person Info in cache: Person [id=1000, name=Soumitra Roy]
26-01-2017 18:22:26.263 [main] INFO  com.roytuts.jcache.test.JCacheTest - Has Person Info removed from cache: false
26-01-2017 18:22:26.357 [main] INFO  com.roytuts.jcache.test.JCacheTest - Is there still any Person Info in the cache: false
26-01-2017 18:22:26.357 [main] INFO  com.roytuts.jcache.test.JCacheTest - Started JCacheTest in 1.703 seconds (JVM running for 2.609)

Thanks for reading.

Tags:

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials | TwitterFacebook Google PlusLinkedin | Reddit | Email Me

Leave a Reply

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