JSR-107 JCache compatibility adapter for Caffeine caching library
—
The Management and Monitoring system provides JMX integration for cache statistics, management operations, and runtime monitoring of cache performance and behavior. The system includes comprehensive statistics collection and JMX MBean registration for monitoring tools.
JMX MBean providing comprehensive cache statistics for monitoring cache performance and behavior.
/**
* JMX MBean for cache statistics implementing JSR-107 CacheStatisticsMXBean
*/
public final class JCacheStatisticsMXBean implements CacheStatisticsMXBean {
/**
* Check if statistics collection is enabled
* @return true if statistics are being collected
*/
public boolean isEnabled();
/**
* Get the number of cache hits
* @return total number of successful cache retrievals
*/
public long getCacheHits();
/**
* Get the number of cache misses
* @return total number of failed cache retrievals
*/
public long getCacheMisses();
/**
* Get the total number of get operations
* @return total number of cache get operations (hits + misses)
*/
public long getCacheGets();
/**
* Get the number of cache puts
* @return total number of cache put operations
*/
public long getCachePuts();
/**
* Get the number of cache removals
* @return total number of cache remove operations
*/
public long getCacheRemovals();
/**
* Get the number of cache evictions
* @return total number of entries evicted from cache
*/
public long getCacheEvictions();
/**
* Get the average time for get operations in microseconds
* @return average get operation time
*/
public float getAverageGetTime();
/**
* Get the average time for put operations in microseconds
* @return average put operation time
*/
public float getAveragePutTime();
/**
* Get the average time for remove operations in microseconds
* @return average remove operation time
*/
public float getAverageRemoveTime();
/**
* Get the cache hit percentage
* @return percentage of successful cache retrievals (0-100)
*/
public float getCacheHitPercentage();
/**
* Get the cache miss percentage
* @return percentage of failed cache retrievals (0-100)
*/
public float getCacheMissPercentage();
}Usage Examples:
// Enable statistics on cache
CaffeineConfiguration<String, String> config = new CaffeineConfiguration<String, String>()
.setTypes(String.class, String.class)
.setStatisticsEnabled(true);
Cache<String, String> cache = cacheManager.createCache("monitoredCache", config);
// Statistics are automatically collected
cache.put("key1", "value1");
cache.put("key2", "value2");
String value = cache.get("key1"); // Hit
String missing = cache.get("key3"); // Miss
// Access statistics via JMX or programmatically
CacheStatisticsMXBean stats = cache.unwrap(CacheProxy.class)
.getConfiguration(CaffeineConfiguration.class)
.getStatisticsMXBean();
System.out.println("Cache hits: " + stats.getCacheHits());
System.out.println("Cache misses: " + stats.getCacheMisses());
System.out.println("Hit percentage: " + stats.getCacheHitPercentage() + "%");JMX MBean for cache management operations and configuration access.
/**
* JMX MBean for cache management implementing JSR-107 CacheMXBean
*/
public final class JCacheMXBean implements CacheMXBean {
/**
* Get the cache key type name
* @return fully qualified name of the key type
*/
public String getKeyType();
/**
* Get the cache value type name
* @return fully qualified name of the value type
*/
public String getValueType();
/**
* Check if read-through is enabled
* @return true if read-through is enabled
*/
public boolean isReadThrough();
/**
* Check if write-through is enabled
* @return true if write-through is enabled
*/
public boolean isWriteThrough();
/**
* Check if store-by-value is enabled
* @return true if store-by-value is enabled
*/
public boolean isStoreByValue();
/**
* Check if statistics collection is enabled
* @return true if statistics are enabled
*/
public boolean isStatisticsEnabled();
/**
* Check if management is enabled
* @return true if management is enabled
*/
public boolean isManagementEnabled();
}Utility for JMX MBean registration and unregistration with proper naming and lifecycle management.
/**
* Utility for JMX MBean registration and unregistration
*/
public final class JmxRegistration {
/**
* MBean types for registration
*/
public enum MBeanType {
CONFIGURATION, STATISTICS
}
/**
* Register an MXBean for the specified cache
* @param cache the cache to register MBean for
* @param mxBean the MXBean instance to register
* @param mBeanType the type of MBean being registered
*/
public static void registerMxBean(Cache<?, ?> cache, Object mxBean, MBeanType mBeanType);
/**
* Unregister an MXBean for the specified cache
* @param cache the cache to unregister MBean for
* @param mBeanType the type of MBean being unregistered
*/
public static void unregisterMxBean(Cache<?, ?> cache, MBeanType mBeanType);
}Usage Examples:
Cache<String, String> cache = cacheManager.createCache("managedCache", config);
// Enable management (automatically registers MBeans)
cacheManager.enableManagement("managedCache", true);
cacheManager.enableStatistics("managedCache", true);
// Manual MBean registration (not typically needed)
JCacheMXBean managementBean = new JCacheMXBean(cache);
JmxRegistration.registerMxBean(cache, managementBean, JmxRegistration.MBeanType.CONFIGURATION);
// Access via JMX client or programmatically
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = new ObjectName(
"javax.cache:type=CacheConfiguration" +
",CacheManager=" + cache.getCacheManager().getURI() +
",Cache=" + cache.getName());
String keyType = (String) mBeanServer.getAttribute(objectName, "KeyType");
Boolean isStoreByValue = (Boolean) mBeanServer.getAttribute(objectName, "StoreByValue");Configure statistics collection behavior and granularity.
// Enable standard JSR-107 statistics
CaffeineConfiguration<String, String> standardStats = new CaffeineConfiguration<String, String>()
.setStatisticsEnabled(true);
// Enable native Caffeine statistics for additional metrics
CaffeineConfiguration<String, String> nativeStats = new CaffeineConfiguration<String, String>()
.setStatisticsEnabled(true)
.setNativeStatisticsEnabled(true);
Cache<String, String> cache = cacheManager.createCache("statsCache", nativeStats);Integration with monitoring systems and frameworks.
// Micrometer integration example
MeterRegistry meterRegistry = new SimpleMeterRegistry();
Cache<String, String> cache = cacheManager.getCache("monitoredCache");
CacheStatisticsMXBean stats = /* get statistics bean */;
// Register metrics
Gauge.builder("cache.hits")
.description("Cache hit count")
.register(meterRegistry, stats, CacheStatisticsMXBean::getCacheHits);
Gauge.builder("cache.hit.ratio")
.description("Cache hit ratio")
.register(meterRegistry, stats, s -> s.getCacheHitPercentage() / 100.0);
Timer.builder("cache.get")
.description("Cache get operation time")
.register(meterRegistry);Monitor cache performance characteristics and optimization opportunities.
public class CachePerformanceMonitor {
private final CacheStatisticsMXBean statistics;
private final ScheduledExecutorService scheduler;
public CachePerformanceMonitor(Cache<?, ?> cache) {
this.statistics = cache.unwrap(CacheProxy.class)
.getStatistics();
this.scheduler = Executors.newScheduledThreadPool(1);
}
public void startMonitoring() {
scheduler.scheduleAtFixedRate(this::reportMetrics, 0, 60, TimeUnit.SECONDS);
}
private void reportMetrics() {
System.out.println("=== Cache Performance Report ===");
System.out.println("Hits: " + statistics.getCacheHits());
System.out.println("Misses: " + statistics.getCacheMisses());
System.out.println("Hit Ratio: " + String.format("%.2f%%", statistics.getCacheHitPercentage()));
System.out.println("Avg Get Time: " + String.format("%.2f μs", statistics.getAverageGetTime()));
System.out.println("Avg Put Time: " + String.format("%.2f μs", statistics.getAveragePutTime()));
System.out.println("Evictions: " + statistics.getCacheEvictions());
// Check for performance issues
if (statistics.getCacheHitPercentage() < 80.0f) {
System.out.println("WARNING: Low hit ratio detected!");
}
if (statistics.getAverageGetTime() > 1000.0f) {
System.out.println("WARNING: High get latency detected!");
}
}
}Complete JMX integration for enterprise monitoring tools.
// JMX ObjectName format for cache MBeans
// Configuration MBean:
// javax.cache:type=CacheConfiguration,CacheManager=<uri>,Cache=<name>
// Statistics MBean:
// javax.cache:type=CacheStatistics,CacheManager=<uri>,Cache=<name>
public class JmxCacheMonitor {
public void monitorCache(String cacheManagerUri, String cacheName) throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// Access configuration MBean
ObjectName configName = new ObjectName(
"javax.cache:type=CacheConfiguration" +
",CacheManager=" + cacheManagerUri +
",Cache=" + cacheName);
// Access statistics MBean
ObjectName statsName = new ObjectName(
"javax.cache:type=CacheStatistics" +
",CacheManager=" + cacheManagerUri +
",Cache=" + cacheName);
// Query configuration
String keyType = (String) mBeanServer.getAttribute(configName, "KeyType");
String valueType = (String) mBeanServer.getAttribute(configName, "ValueType");
Boolean readThrough = (Boolean) mBeanServer.getAttribute(configName, "ReadThrough");
Boolean writeThrough = (Boolean) mBeanServer.getAttribute(configName, "WriteThrough");
// Query statistics
Long hits = (Long) mBeanServer.getAttribute(statsName, "CacheHits");
Long misses = (Long) mBeanServer.getAttribute(statsName, "CacheMisses");
Float hitPercentage = (Float) mBeanServer.getAttribute(statsName, "CacheHitPercentage");
Float averageGetTime = (Float) mBeanServer.getAttribute(statsName, "AverageGetTime");
System.out.println("Cache Configuration:");
System.out.println(" Key Type: " + keyType);
System.out.println(" Value Type: " + valueType);
System.out.println(" Read Through: " + readThrough);
System.out.println(" Write Through: " + writeThrough);
System.out.println("Cache Statistics:");
System.out.println(" Hits: " + hits);
System.out.println(" Misses: " + misses);
System.out.println(" Hit Percentage: " + hitPercentage + "%");
System.out.println(" Average Get Time: " + averageGetTime + " μs");
}
}Implement health checks for cache monitoring and alerting.
public class CacheHealthCheck {
private final Cache<?, ?> cache;
private final CacheStatisticsMXBean statistics;
public CacheHealthCheck(Cache<?, ?> cache) {
this.cache = cache;
this.statistics = cache.unwrap(CacheProxy.class).getStatistics();
}
public HealthStatus checkHealth() {
if (cache.isClosed()) {
return HealthStatus.unhealthy("Cache is closed");
}
if (!statistics.isEnabled()) {
return HealthStatus.healthy("Cache operational (statistics disabled)");
}
float hitPercentage = statistics.getCacheHitPercentage();
float averageGetTime = statistics.getAverageGetTime();
if (hitPercentage < 50.0f) {
return HealthStatus.unhealthy("Low hit ratio: " + hitPercentage + "%");
}
if (averageGetTime > 5000.0f) {
return HealthStatus.unhealthy("High latency: " + averageGetTime + " μs");
}
return HealthStatus.healthy("Cache performing well");
}
}Set up alerting based on cache metrics and thresholds.
public class CacheAlerting {
public void setupAlerts(Cache<?, ?> cache) {
CacheStatisticsMXBean stats = cache.unwrap(CacheProxy.class).getStatistics();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
try {
checkHitRatio(stats);
checkLatency(stats);
checkEvictionRate(stats);
} catch (Exception e) {
sendAlert("Cache monitoring error: " + e.getMessage());
}
}, 0, 5, TimeUnit.MINUTES);
}
private void checkHitRatio(CacheStatisticsMXBean stats) {
float hitRatio = stats.getCacheHitPercentage();
if (hitRatio < 80.0f) {
sendAlert("Cache hit ratio below threshold: " + hitRatio + "%");
}
}
private void checkLatency(CacheStatisticsMXBean stats) {
float avgGetTime = stats.getAverageGetTime();
if (avgGetTime > 1000.0f) {
sendAlert("Cache latency above threshold: " + avgGetTime + " μs");
}
}
private void checkEvictionRate(CacheStatisticsMXBean stats) {
long evictions = stats.getCacheEvictions();
long gets = stats.getCacheGets();
if (gets > 0 && (evictions * 100.0 / gets) > 10.0) {
sendAlert("High eviction rate detected: " +
String.format("%.2f%%", evictions * 100.0 / gets));
}
}
private void sendAlert(String message) {
// Send alert to monitoring system
System.err.println("ALERT: " + message);
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-github-ben-manes-caffeine--jcache