Spring Boot 2.x Batch应用如何获取Micrometer缓存指标写入日志
实现方案
你可以通过两种方式获取Ehcache统计数据,无需依赖Actuator接口暴露能力,以下是具体实现:
方案1:直接从Ehcache原生API获取(推荐,性能损耗更低)
这种方式直接调用Ehcache内置的统计能力,不需要依赖Micrometer的封装,适合你的离线批处理场景。
你注入的CacheManager是JSR107标准的javax.cache.CacheManager,直接将获取到的缓存实例转为Ehcache原生实现即可拿到统计对象:
import javax.cache.Cache; import javax.cache.CacheManager; import org.ehcache.jsr107.Eh107Cache; import org.ehcache.core.statistics.CacheStatistics; import lombok.extern.slf4j.Slf4j; @Slf4j public class MyListener { @Autowired CacheManager mgr; // 你可以配合@Scheduled注解实现定期统计,记得启动类加@EnableScheduling开启定时任务 public void dumpAllCacheStats() { mgr.getCacheNames().forEach(this::writeCacheStats); } void writeCacheStats(String cacheName) { Cache<?, ?> cache = mgr.getCache(cacheName); if (cache == null) { return; } // 转换为Ehcache原生实现类获取统计 Eh107Cache<?, ?> ehcache = cache.unwrap(Eh107Cache.class); CacheStatistics stats = ehcache.getRuntimeConfiguration().getCacheStatistics(); // 按需取你需要的统计字段即可 long hits = stats.getCacheHits(); long misses = stats.getCacheMisses(); double hitRate = stats.getCacheHitPercentage(); long putCount = stats.getCachePuts(); long evictionCount = stats.getCacheEvictions(); long currentSize = stats.getSize(); // 输出日志,可根据需要改为结构化日志格式 log.info("缓存[{}]统计数据:命中数={}, 未命中数={}, 命中率={}%, 写入数={}, 淘汰数={}, 当前容量={}", cacheName, hits, misses, hitRate, putCount, evictionCount, currentSize); } }
方案2:从Micrometer的MeterRegistry获取已采集的指标
如果你需要和其他Micrometer采集的指标保持口径统一,可以直接从容器注入的MeterRegistry中读取已自动采集的缓存指标:
import io.micrometer.core.instrument.FunctionCounter; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import javax.cache.CacheManager; import lombok.extern.slf4j.Slf4j; @Slf4j public class MyListener { @Autowired CacheManager mgr; @Autowired MeterRegistry meterRegistry; public void dumpAllCacheStats() { mgr.getCacheNames().forEach(this::writeCacheStats); } void writeCacheStats(String cacheName) { // 从Micrometer中读取对应缓存的指标,注意判空避免无操作时指标不存在导致NPE FunctionCounter hits = meterRegistry.find("cache.gets") .tag("cache", cacheName) .tag("result", "hit") .functionCounter(); FunctionCounter misses = meterRegistry.find("cache.gets") .tag("cache", cacheName) .tag("result", "miss") .functionCounter(); FunctionCounter puts = meterRegistry.find("cache.puts") .tag("cache", cacheName) .functionCounter(); FunctionCounter evictions = meterRegistry.find("cache.evictions") .tag("cache", cacheName) .functionCounter(); Gauge size = meterRegistry.find("cache.size") .tag("cache", cacheName) .gauge(); long hitCount = hits != null ? (long) hits.count() : 0; long missCount = misses != null ? (long) misses.count() : 0; double hitRate = hitCount + missCount == 0 ? 0 : (double) hitCount / (hitCount + missCount) * 100; long putCount = puts != null ? (long) puts.count() : 0; long evictionCount = evictions != null ? (long) evictions.count() : 0; long currentSize = size != null ? (long) size.value() : 0; log.info("缓存[{}]统计数据:命中数={}, 未命中数={}, 命中率={}%, 写入数={}, 淘汰数={}, 当前容量={}", cacheName, hitCount, missCount, hitRate, putCount, evictionCount, currentSize); } }
注意事项
如果你注入的是Spring封装的org.springframework.cache.CacheManager,需要先调用getCache(cacheName).getNativeCache()拿到JSR107标准的Cache实例,再做后续转换操作即可。
内容的提问来源于stack exchange,提问作者user944849
相关产品推荐
相关产品推荐

