Backend Development 8 min read

Master Spring Boot Caching with JSR‑107 and Ehcache: Step‑by‑Step Guide

Learn how to enable and configure transparent caching in Spring Boot 2.3 using JSR‑107 annotations and Ehcache, covering annotation usage, custom key generators, service and controller implementation, Maven dependencies, YAML and XML settings, and practical testing of cache put, get, and removal operations.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Boot Caching with JSR‑107 and Ehcache: Step‑by‑Step Guide

Environment: springboot2.3.12.RELEASE + JSR107 + Ehcache + JPA

Since Spring 3.1 the framework provides transparent caching support. From Spring 4.1 the cache abstraction supports JSR‑107 annotations and more customization.

Method 1: Using Spring annotations

Spring provides the following annotations:

@Cacheable – triggers caching

@CacheEvict – triggers cache eviction

@CachePut – updates cache without affecting method execution

@Caching – combines multiple cache operations on a method

@CacheConfig – class‑level shared cache configuration

Add the dependency:

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  &lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt;
&lt;/dependency&gt;
</code>

Service method example:

<code>@Service
public class StorageService {
  @Resource
  private StorageRepository sr;

  @Cacheable(value = {"cache_storage"}, keyGenerator = "storageKey")
  public Storage getStorage(Long id) {
    return sr.findById(id).get();
  }
}
</code>

Custom key generator:

<code>@Component("storageKey")
public class StorageKeyGenerator implements KeyGenerator {
  private static final String KEY_PREFIX = "storage_";

  @Override
  public Object generate(Object target, Method method, Object... params) {
    StringBuilder sb = new StringBuilder();
    for (Object param : params) {
      sb.append(param);
    }
    return KEY_PREFIX + sb.toString();
  }
}
</code>

Controller example:

<code>@RestController
@RequestMapping("/storages")
public class StorageController {
  @Resource
  private StorageService storageService;

  @GetMapping("/{id}")
  public Object get(@PathVariable("id") Long id) {
    return storageService.getStorage(id);
  }
}
</code>

First request shows SQL output; subsequent request shows no SQL, confirming cache works.

JSR‑107 annotations can also be used with Ehcache.

Method 2: Using JSR‑107 and Ehcache

Correspondence table between Spring and JSR‑107 annotations (image).

Add Maven dependencies:

<code>&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
  &lt;artifactId&gt;spring-boot-starter-cache&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;groupId&gt;mysql&lt;/groupId&gt;
  &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;groupId&gt;org.ehcache&lt;/groupId&gt;
  &lt;artifactId&gt;ehcache&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;groupId&gt;javax.cache&lt;/groupId&gt;
  &lt;artifactId&gt;cache-api&lt;/artifactId&gt;
&lt;/dependency&gt;
</code>

Service using JSR‑107 annotations:

<code>@Service
public class StorageService {
  @Resource
  private StorageRepository sr;

  @Transactional
  @CachePut(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)
  public Storage save(@CacheValue Storage storage) {
    return sr.saveAndFlush(storage);
  }

  @CacheResult(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)
  public Storage getStorage(Long id) {
    return sr.findById(id).get();
  }

  @Transactional
  @CacheRemove(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)
  public void removeStorage(Long id) {
    sr.deleteById(id);
  }

  @Transactional
  @CachePut(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)
  public Storage updateStorage(@CacheValue Storage storage) {
    return sr.saveAndFlush(storage);
  }
}
</code>

Custom JCacheKeyGenerator (code illustration).

application.yml configuration:

<code>spring:
  cache:
    cacheNames:
      - cache_storage
    ehcache:
      config: classpath:ehcache.xml
</code>

ehcache.xml configuration:

<code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false"&gt;
  &lt;diskStore path="java.io.tmpdir/Tmp_EhCache"/&gt;
  &lt;defaultCache eternal="false" maxElementsInMemory="10000"
                overflowToDisk="false" diskPersistent="false"
                timeToIdleSeconds="1800" timeToLiveSeconds="259200"
                memoryStoreEvictionPolicy="LRU"/&gt;
  &lt;cache name="cache_storage" eternal="false" maxElementsInMemory="5000"
         overflowToDisk="false" diskPersistent="false"
         timeToIdleSeconds="1800" timeToLiveSeconds="1800"
         memoryStoreEvictionPolicy="LRU"/&gt;
&lt;/ehcache&gt;
</code>

Testing add, update, delete:

Add a record (console output).

Query the newly added ID shows no SQL, confirming @CachePut works.

Delete the record (image).

Subsequent query generates SQL, indicating cache was evicted.

All steps demonstrate successful caching, cache update, and eviction using Spring annotations and JSR‑107 with Ehcache.

JavaBackend DevelopmentCachingSpring BootEhcacheJSR-107
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.