You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 03:36:04