Spring Boot EhCache Example – Complete Guide

Spring Boot EhCache Example

In this article of Spring Boot, We will learn how to configure the EhCache 3.x in Spring Boot Application.

In this Spring Boot EhCache Example , we will also learn how to use cache config which is annotation based as well as how to use CacheManager to manually updating the cache.

EhCache is a popular method for Spring boot Caching process.

Let’s get started :

Add Required Maven dependencies

In the below example of Spring Boot EhCache, we are using the version 2.1.6.RELEASE of Spring Boot and version 3 of EhCache.

The earlier versions of Spring Boot does not supports the EhCache version 3. They only supports EhCache 2.x versions which are available under the package net.sf.ehcache.

However, The new versions of Spring Boot does support the EhCache version 3.x which is available under org.ehcache package.

The version 3 of Ehcache is basically an implementation of a JSR-107 , which is a cache manager.

For Spring Boot EhCache example project, we need to add the below listed dependencies in our project:

  • spring-boot-starter-cache
  • ehcache (org.ehcache)
  • cache-api (javax.cache)

Below is our pom.xml file :

<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.example</groupId>
    <artifactId>SpringEhcache</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>SpringBootEhcache</name>
    <url>http://maven.apache.org</url>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath />
    </parent>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <skipTests>true</skipTests>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.cache</groupId>
            <artifactId>cache-api</artifactId>
        </dependency>
    </dependencies>
     
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Configuration of EhCache in Spring Boot Project

As we know, Spring Boot auto-configuration is very effective and useful feature. Auto-configuration of Spring Boot finds the implementation of JSR-107 of EhCache.

However, default caches are not created by Spring Boot. The reason is because Spring and even EhCache never looks for any default ehcache.xml.

To be able to use the EhCache, we need to specify the file path of ehcache configuration file in the application.properties.

Below is the property needs to be added in the application.properties :

spring.cache.jcache.config=classpath:ehcache.xml

Configurations in ehcache.xml

We need to add the cache names , their attributes etc in the ehcache.xml file.

In the documentation – ehcache documentation, we can find the complete list of attributes for ehcache configuration.

Below is our ehcache.xml :

<config
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xmlns:jsr107='http://www.ehcache.org/v3/jsr107'>
 
    <service>
        <jsr107:defaults enable-statistics="true"/>
    </service>
 
    <cache alias="studentCache">
        <key-type>java.lang.Long</key-type>
        <value-type>com.example.Student</value-type>
        <expiry>
            <ttl unit="seconds">10000</ttl>
        </expiry>
        <listeners>
            <listener>
                <class>com.example.CustomCacheEventLogger</class>
                <event-firing-mode>ASYNCHRONOUS</event-firing-mode>
                <event-ordering-mode>UNORDERED</event-ordering-mode>
                <events-to-fire-on>CREATED</events-to-fire-on>
                <events-to-fire-on>UPDATED</events-to-fire-on>
                <events-to-fire-on>EXPIRED</events-to-fire-on>
                <events-to-fire-on>REMOVED</events-to-fire-on>
                <events-to-fire-on>EVICTED</events-to-fire-on>
            </listener>
        </listeners>
        <resources>
            <heap unit="entries">2000</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache>
</config>

Creating the CacheEventListener

In this example, we are also using the event listener to log the cache events such as creation of cache entries, removal of entries, updation of entries etc.

Below is our CustomCacheEventLogger.java file :

package com.example;
 
import org.ehcache.event.CacheEvent;
import org.ehcache.event.CacheEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class CustomCacheEventLogger implements CacheEventListener<Object, Object> {
 
    private static final Logger LOG = LoggerFactory.getLogger(CustomCacheEventLogger.class);
 
    @Override
    public void onEvent(CacheEvent cacheEvent) {
        LOG.info("Cache event = {}, Key = {},  Old value = {}, New value = {}", cacheEvent.getType(),
                cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
    }
}

@EnableCaching annotation

@EnableCaching annotation is used to enable the Spring Boot’s annotation-driven cache management capability.

It also enables support for the proxy interceptors whenever the  @Cacheable annotated methods are invoked.

Below is our CacheConfig.java file :

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@EnableCaching
public class CacheConfig {
 
}

@Cacheable Annotation

@Cacheable annotation is basically used to cache the data which is returned by a method call.

@Cacheable annotations are method level annotations. We use this on method whose output should be cached.

It has attributes such as cacheNames and key which refer to the cache and key respectively for each cache entry.

Below is our StudentManager.java :

import java.util.HashMap;
 
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
 
@Service
public class StudentManager 
{
    static HashMap<Long, Student> db = new HashMap<>();
     
    static {
        db.put(1, new Student(1, "Tech", "Station"));
        db.put(2, new Student(2, "Blog", "Station"));
    }
     
    @Cacheable(cacheNames="studentCache", key="#id")
    public Student getStudentById(Long id) {
        System.out.println("Getting student from the DB");
        return db.get(id);
    }
}

Spring CacheManager API

In this section, we will learn to use the CacheManager API of Spring Boot.

There may be some cases where we want to use the caching in our application but annotation does not seems to be the perfect answer for it.

Then we can definitely use the Spring CacheManager API which is org.springframework.cache.CacheManager and org.springframework.cache.Cache.

We can use above mentioned APIs abstraction for accessing and utilizing the ehcache for both adding and accessing cache entries.

We need to use the autowire functionality of Spring for CacheManager and then we will use its getCache(name) to retrieve the cache instance by providing its name in the method’s argument.

One we get the access of cacahe, we can use its get() and put() method to add and access entries respectively.

See Below code snippet :

//First, Autowire the CacheManager
 
@Autowired
private CacheManager cacheManager;
 
//Second, access the Cache
 
Cache cache = cacheManager.getCache("cache1");
cache.put(1, "Hey");
String str = cache.get(1).get();

Spring Boot EhCache Example – Demo

Now Let’s create a model class and try to cache their instances and check if it is working or not.

Student.java :

import java.io.Serializable;
 
public class Student implements Serializable 
{
    private static final long serialVersionUID = 5517244812959569947L;
     
    private Long id;
    private String firstName;
    private String lastName;
 
    public Student() {
        super();
    }
 
    public Student(Long id, String firstName, String lastName) {
        super();
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }
 
    //Getters and setters are omitted
 
    @Override
    public String toString() {
        return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
    }
}

Finally, In the Main application class, we are testing the :

  • Manual cache access using CacheManager and
  • Annotation based cache access using @Cacheable annotation.

MainApp.java :

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.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
 
@SpringBootApplication
public class MainApp{
 
    @Autowired
    private CacheManager cacheManager;
     
    @Autowired
    private StudentManager studentManager;
 
    public static void main(String[] args) {
        SpringApplication.run(MainApp.class, args);
    }
 
    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {
             
            //hitting the database 
            System.out.println(studentManager.getStudentById(1));
             
            //hitting the cache 
            System.out.println(studentManager.getStudentById(1));
             
            //Accessing the cache instance by its name
            Cache cache = cacheManager.getCache("studentCache");
             
            //Adding the entry to cache
            cache.put(3, new Student(3, "Tech", "BlogStation"));
             
            //Getting the entry from cache
            System.out.println(cache.get(3).get());
        };
    }
}

Below is the Output :

//First Hitting - studentManager.getStudentById(1)

Getting student from the DB
Student [id=1, firstName=Tech, lastName=Station]
2019-11-12 13:42:23.421  INFO 11345 --- [e [_default_]-0] com.example.CustomCacheEventLogger       
: Cache event = CREATED, Key = 1,  Old value = null, New value = Student [id=1, firstName=Tech, lastName=Station]
 
//Second Hitting to - studentManager.getStudentById(1)

Student [id=1, firstName=Tech, lastName=Station]
 
//Hitting - cache.put(3, new Student(3, "Tech", "BlogStation"));

2019-11-12 13:45:23.423  INFO 11978 --- [e [_default_]-0] com.example.CustomCacheEventLogger       : Cache event = CREATED, Key = 3,  Old value = null, New value = Student [id=3, firstName=Tech, lastName=BlogStation]
 
//Hitting - cache.get(3).get();

Student [id=3, firstName=Tech, lastName=BlogStation]

Conclusion

In this tutorial, we have learnt the complete tutorial for EhCache version 3 setting up with Spring Boot version 2 for Spring Boot Application Caching.

Leave a Reply

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