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