Spring Boot With Ehcache 3 and JSR-107
Bring caching to your Spring Boot apps! To help, we'll use Ehcache 3 and the always-helpful JCache annotations.
Join the DZone community and get the full member experience.
Join For FreeHere we are going to cover how to use Ehcache 3 for caching in Spring Boot based on JSR-107. We will tackle how to do operations on the cache itself (besides the well-known annotation usage).
Before we start, let's highlight 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 JSR-107 annotations.
Steps to Use Ehcache 3 With Spring Boot
Create a Spring Boot Maven project and 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>
Set the spring.cache.jcache.config property to include the classpath and ehcache.xml file. Enable the following in your application.yml file:
Enable caching in the Spring Boot main class:
@SpringBootApplication
//enable Spring Boot caching
@EnableCaching
public class AlertManagerApplication {
public static void main(String[] args) {
SpringApplication.run(AlertManagerApplication.class, args);
}
}
Configure your Ehcache XML file as follows:
<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>
For more information about the XML configuration, please check the following:
The core namespace. The XSD can be found here.
The JSR-107 namespace. The XSD can be found here.
Then you can easily inject the cache manager in your bean class.
@Autowired
//inject the cache manager
private javax.cache.CacheManager cacheManager;
//get access to your cache for further operations by cache name
private Cache < String, List < AlertEntry >> getAlertsCache() {
return cacheManager.getCache(CacheNames.Alerts.name());
}
//close the cache manager upon bean destruction for proper cache file persistence
@PreDestroy
public void close() {
cacheManager.close();
}
Start accessing your caches from the cache manager. If you want to do direct operations over it like below, please check EhcacheAlertsStore.java in the GitHub project for more details.
@Override
// if you want to do atomic updates over the 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 updates 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 the API design, nothing is needed here
return null;
});
}
The complete code sample for testing is on GitHub, where you can run it and play with REST APIs for cache operations via the generated runtime Swagger.
References
- Ehcache 3.0 Documentation
- Spring Cache Abstraction
- Spring Cache Abstraction, JCache (JSR-107) annotations
Published at DZone with permission of Mahmoud Romeh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments