I actually thought that the following task "get hands on a cache" should be daily bread for an enterprise application and therefore rather easy to implement. But I guess I was wrong. Apart from completely outdated tutorials and some code snippets that are not applicable for a modern Spring Boot application, there is nothing to be found.
The tech stack used is as follows:
- Spring Boot 3
- Hibernate 6
- JCache (Ehcache 3)
Hibernate is set to use hibernate-jcache
, which in turn uses ehcache
. The challenge is to get access to individual cache regions in order to clear them manually. It would also be nice to find out how many entries the cache currently holds. Sounds like an everyday task.
pom.xml excerpt:
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<classifier>jakarta</classifier>
</dependency>
ehcache.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="http://www.ehcache.org/v3
http://www.ehcache.org/schema/ehcache-core.xsd">
<cache-template name="status-cache">
<expiry><ttl>3600</ttl></expiry>
<resources>
<heap>10</heap>
<offheap unit="MB">1</offheap>
</resources>
</cache-template>
<cache alias="email-status-cache" uses-template="status-cache"/>
</config>
Spring Boot properties' application.yml:
spring.jpa.properties:
-hibernate.cache.region.factory_class: "org.hibernate.cache.jcache.internal.JCacheRegionFactory"
-hibernate.cache.use_second_level_cache: true
-hibernate.javax.cache.provider: "org.ehcache.jsr107.EhcacheCachingProvider"
-hibernate.javax.missing_cache_strategy: fail
-hibernate.javax.cache.uri: "classpath:ehcache.xml"
-hibernate.generate_statistics: true
-jakarta.persistence.sharedCache.mode: ENABLE_SELECTIVE
Cacheable entity class EmailStatus:
@Entity
@Immutable
@Access(AccessType.FIELD)
@org.hibernate.annotations.Cache(region = "email-status-cache",
usage = CacheConcurrencyStrategy.READ_ONLY)
@Table(name = "email_status")
public class EmailStatus implements Serializable {
//...
}
So far so good. The caching works and I can also access the statistics via JMX as follows:
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
try {
Set<ObjectInstance> cacheBeans = mBeanServer.queryMBeans(ObjectName.getInstance("javax.cache:type=CacheStatistics,CacheManager=*,Cache=*"), null);
for (ObjectInstance cacheBean : cacheBeans) {
CacheStatisticsMXBean cacheStatisticsMXBean = JMX.newMBeanProxy(mBeanServer, cacheBean.getObjectName(), CacheStatisticsMXBean.class);
logger.info(cacheStatisticsMXBean.getCacheHits());
}
} catch (MalformedObjectNameException e) { }
And now I want to get hands on the cache itself.
The first attempt was to inject org.springframework.cache.CacheManager
to retrieve the cache:
Cache cache = cacheManager.getCache("email-status-cache");
Unfortunately, the cache object retrieved is null
. So this doesn't seem to work.
The next attempt was to inject org.springframework.cache.jcache.JCacheCacheManager
to retrieve the cache:
Cache cache = jCacheCacheManager.getCache("email-status-cache");
Well, you guess right, the retrieved cache is also null
.
Now a third attempt, desperately trying code snippets I've found. This time I try to access tier statistics directly through Ehcache service:
StatisticsService service = new DefaultStatisticsService();
org.ehcache.CacheManager cm = CacheManagerBuilder.newCacheManagerBuilder().using(service).build();
cm.init();
CacheStatistics stats = service.getCacheStatistics("email-status-cache");
long heapCount = stats.getTierStatistics().get("Onheap").getMappings();
And here the answer is an IllegalArgumentException: Unknown cache: email-status-cache
. So none of my attempts to get access to the cache works. Providing the fully qualified name instead of the cache alias doesn't make any difference. So for now, I am out of any clues.
Does anybody know how to obtain an Ehcache 3 cache, implemented through a JCache facade for Hibernate 6 in Spring Boot 3?