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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!– 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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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