Spring Boot With Ehcache

Spring Caching provides an easy approach to add caching into an existing Spring application. In this article, we will look at an example of using Ehcache with Spring Boot.

 

Introduction

Spring offers support for two sets of annotations for caching. The original one are available with Spring 3.1+, while the JSR-107 introduced with Spring 4.1+. It has significantly improved the cache abstraction with the support of JSR-107 annotations and more customization options. In this article we will learn how to use Ehcache with Spring application. We will use Ehcache version 3 for our examples.

Read our article Spring caching for a further knowledge of Spring caching layer.

 

1. Project Setup

Spring Boot provides auto-configuration support for the Cache providers. If we have not to defined a bean of type CacheManager or a CacheResolver named cacheResolver, Spring Boot tries to detect the caching API based on the jars in the classpath. We will use Spring Boot for this article, but steps are similar for simple Spring application.

 

1.1 Maven dependencies

This is how our pom.xml look like:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.javadevjournal</groupId>
    <artifactId>spring-boot-ehcache</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Spring Boot With Ehcache</name>
    <description>Spring Boot With Ehcache</description>
    <properties>
        <java.version>1.8</java.version>
        <ehcache-version>3.6.1</ehcache-version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>${ehcache-version}</version>
        </dependency>
        <dependency>
            <groupId>javax.cache</groupId>
            <artifactId>cache-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Let’s quickly look at some significant points:

  1. Added caching support with Spring Boot using the spring-boot-starter-cache.
  2. Add Ehcache 3.
  3. Add the jar for the JSR-107 API.

 

2. Ehcache Configuration

Spring’s auto-configuration finds Ehcache’s implementation of JSR-107. However, no caches created by default. Set the spring.cache.jcache.config property to include the classpath and ehcache.xml file to tell Spring where to find it.

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

Next step is to set up the caching for our Spring application. The best and most flexible approach is to use @EnableCaching annotation:

@SpringBootApplication
@EnableCaching
public class SpringBootWithEhcacheApplication {

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

To enable caching based on the XML configuration, use the <cache:annotation-driven /> tag:

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

 

2.1 Defining ehcache.xml file

Let’s create an ehcache.xml file with a cache called customer:

<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="customer">
        <key-type>java.lang.Long</key-type>
        <value-type>com.javadevjournal.data.Customer</value-type>
        <expiry>
            <ttl unit="seconds">10</ttl>
        </expiry>
        <listeners>
            <listener>
                <class>com.javadevjournal.config.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>

 

2.2 Custom Listener

Let’s add a custom cache event listener to log the information. This is how our custom listener look like:

public class CustomCacheEventLogger implements CacheEventListener<Object, Object> {

    private static final Logger LOG= LoggerFactory.getLogger(CustomCacheEventLogger.class);
    @Override
    public void onEvent(CacheEvent cacheEvent) {
        LOG.info("custom Caching event {} {} {} {} ", cacheEvent.getType(),cacheEvent.getKey(),cacheEvent.getOldValue(),cacheEvent.getNewValue());
    }
}

You can still use the EventLogger(org.terracotta.ehcache.EventLogger) available with Ehcache

 

3. Example Application

To test our application, let’s create a simple REST controller which will call the customer services to return a customer object.

@RestController
@RequestMapping("/customers")
public class CustomerController {

    @Autowired
    private CustomerService customerService;

    @GetMapping("/customer/{id}")
    public Customer getCustomer(@PathVariable Long id){
        return customerService.getCustomer(id);
    }
}

This is how our CustomerService class look like:

@Cacheable(cacheNames = "customer",key="#id")
    public Customer getCustomer(final Long id){
    LOG.info("Returning customer information for customer id {} ",id);
    Customer customer = new Customer();
    customer.setCustomerId(id);
    customer.setFirstName("Test");
    customer.setLastName("User");
    customer.setEmail("[email protected]");
    return  customer;
}

We annotated the method will @Cacheable annotation. This annotation let Spring handle caching for our application.

 

4. Running the Application

Let’s build and run our application to see Spring with Ehcache 3 in action. Once your application start, go to  http://localhost:8080/customers/customer/1 , you will have the following output from the controller:

{
"customerId": 1,
"firstName": "Test",
"lastName": "User",
"email": "[email protected]"
}

Check the server console, you will have the following output in the console:

2019-02-26 20:48:22.267  INFO 88901 --- [nio-8080-exec-5] c.j.service.CustomerService              : Returning customer information for customer id 1 
2019-02-26 20:48:22.267  INFO 88901 --- [e [_default_]-2] c.j.config.CustomCacheEventLogger        : custom Caching event CREATED 1 null [email protected]

Let’s try to see few critical points here:

  1. This was the first call to the API and there was no data with Ehcache.
  2. The second line shows that Spring caching API created cache entry with Ehcache.
  3. If you refresh the browser, there will be no new log output as Spring will serve the data from the cache (avoid method call).

We have set the cache ttl (time to live) to 10 seconds, refresh the browser after 10 seconds, you will have following output on the console.

2019-02-26 20:53:51.785  INFO 88901 --- [nio-8080-exec-8] c.j.service.CustomerService              : Returning customer information for customer id 1 
2019-02-26 20:53:51.785  INFO 88901 --- [e [_default_]-3] c.j.config.CustomCacheEventLogger        : custom Caching event EXPIRED 1 [email protected] null 
2019-02-26 20:53:51.786  INFO 88901 --- [e [_default_]-3] c.j.config.CustomCacheEventLogger        : custom Caching event CREATED 1 null [email protected]

This happens because after 10 seconds, the cache entry expired, our cache API performed 2 calls:

  1. Expired Event to remove invalid entry from cache.
  2. New/update data added to the cache through a new-created event.

 

Summary

In this article, we show to set up Ehcache with Spring Boot. We saw the different steps to integrate Ehcache 3 with your Spring application. The source code for this article is available on GitHub.

Umesh

Hello!! I am Umesh- an engineer by profession and a photographer by passion.I like to build stuff on the web using OSS and love to capture the world through my lens.

follow me on:

Leave a Reply

avatar

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

  Subscribe  
Notify of