Here we are going to cover how to use Ehcache 3 as a Spring caching in Spring boot based into JSR-107, before we start we need to just highlight what us JSR-107 :
JSR-107(JCache) Annotations:
In regards to caching, Spring offers support for two sets of annotations that can be used to implement caching. You have the original Spring annotations and the new JSR-107 annotations, for more information you can check :
https://spring.io/blog/2014/04/14/cache-abstraction-jcache-jsr-107-annotations-support
Steps to use EhCache3 with Spring boot :
1- Create a spring boot maven project
2- Add the following maven dependencies in your pom.xml along with spring boot dependencies
| <!-- ehcache and JSR dependencies--> | |
| <dependency> | |
| <groupId>org.ehcache</groupId> | |
| <artifactId>ehcache</artifactId> | |
| <version>${ehcache}</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>javax.cache</groupId> | |
| <artifactId>cache-api</artifactId> | |
| </dependency> | |
| <!-- spring boot cache starter--> | |
| <dependency> | |
| <groupId>org.springframework.boot</groupId> | |
| <artifactId>spring-boot-starter-cache</artifactId> | |
| </dependency> |
3- Set the spring.cache.jcache.config property to include the classpath and ehcache.xml file, enable the following in application.yml file

4- Enable caching in spring boot main class
| @SpringBootApplication | |
| // enable spring boot caching | |
| @EnableCaching | |
| public class AlertManagerApplication { | |
| public static void main(String[] args) { | |
| SpringApplication.run(AlertManagerApplication.class, args); | |
| } | |
| } |
5- Configure your EhCache xml file as the following
| <config | |
| xmlns:jsr107='http://www.ehcache.org/v3/jsr107' | |
| xmlns='http://www.ehcache.org/v3'> | |
| <service> | |
| <jsr107:defaults enable-management="true" enable-statistics="true"/> | |
| </service> | |
| <!-- file persistance enabling--> | |
| <persistence directory="./cache"></persistence> | |
| <!-- the 2 caches we will create--> | |
| <cache alias="AlertsConfig" uses-template="config-cache"/> | |
| <cache alias="Alerts" uses-template="alerts-template"/> | |
| <!-- the config cache tenplate--> | |
| <cache-template name="config-cache"> | |
| <listeners> | |
| <listener> | |
| <!-- the the main cache event listener--> | |
| <class>com.demo.alertmanager.services.CacheEventLogger</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>1</heap> | |
| <offheap unit="MB">1</offheap> | |
| <disk persistent="true" unit="MB">100</disk> | |
| </resources> | |
| </cache-template> | |
| <cache-template name="alerts-template"> | |
| <listeners> | |
| <listener> | |
| <class>com.demo.alertmanager.services.CacheEventLogger</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>1</heap> | |
| <offheap unit="MB">1</offheap> | |
| <disk persistent="true" unit="MB">100</disk> | |
| </resources> | |
| </cache-template> | |
| </config> | |
- the core namespace, the xsd can be found here: http://www.ehcache.org/schema/ehcache-core-3.0.xsd
- The JSR-107 namespace, the xsd can be found here: http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd
- XML Configuration Documentation: http://www.ehcache.org/documentation/3.0/xml.html
6- Then you can easily inject the cache manger in your bean class if you do not want to use just simple annotations to enable caching for your operations
| @Autowired | |
| private javax.cache.CacheManager cacheManager; | |
| // get access to your cache for further operation | |
| private Cache<String, List<AlertEntry>> getAlertsCache() { | |
| return cacheManager.getCache(CacheNames.Alerts.name()); | |
| } | |
| // close the cache manager upon shutting down | |
| @PreDestroy | |
| public void close(){ | |
| cacheManager.close(); | |
| } |
7- Start accessing your caches from cache manager if you want to do direct operation over it like below , please check EhcacheAlertsStore.java in the GitHub project for more information
| @Override | |
| // if you want to do atomic update over cache entry | |
| public void updateAlertEntry(String serviceId, String serviceCode, AlertEntry alertEntry) { | |
| //get the JSR cache reference | |
| final Cache<String, List<AlertEntry>> alertsCache = getAlertsCache(); | |
| // then invoke atomic update on the cache entry | |
| alertsCache.invoke(serviceId, (mutableEntry, objects) -> { | |
| if (mutableEntry.exists() && mutableEntry.getValue() != null) { | |
| logger.debug("updating alert entry into the cache store invoke: {},{}",serviceId,serviceCode); | |
| final List<AlertEntry> alertEntries = mutableEntry.getValue(); | |
| // remove only if it has the error code | |
| alertEntries.removeIf(alertEntry1 -> alertEntry1.getErrorCode().equals(serviceCode)); | |
| alertEntries.add(alertEntry); | |
| mutableEntry.setValue(alertEntries); | |
| }else{ | |
| throw new ResourceNotFoundException(String.format("Alert for %s with %s not found", serviceId,serviceCode)); | |
| } | |
| // by api design nothing needed here | |
| return null; | |
| }); | |
| } |
8- Complete code sample for testing is on GitHub where you can run it and play with the REST APIs for cache operations via the generated run-time swagger :
https://github.com/Romeh/spring-boot-web-Ehchache-3-Persistance
References :
- Ehcache 3.0 Documentation
- Spring Cache Abstraction
- Spring Cache Abstraction, JCache (JSR-107) annotations