昨天我在开发后台管理系统的时候,想开发一个缓存清理功能,2个接口,一个接口获取缓存信息,一个接口清空缓存,用的也是 Caffeine 做缓存。
一开始写的时候没想到要加入监控数据,但是在 debug 的时候发现有个 com.github.benmanes.caffeine.cache.Cache.stats() 方法可以获取缓存监控信息,然后就高高兴兴的加入进去了,接口功能都写好后,发现我得到的监控统计数据都是0,然后就 debug 看看为什么为0。

1. 查找问题
刚开始走了弯路,调试到一个SSSMW 类似这样的类,然后发现调用了 com.github.benmanes.caffeine.cache.BoundedLocalCache#statsCounter() 这样一个方法,而方法的内容是
1  | 
  | 
这看起来就不对了,这个方法直接写死了是 disabled 的,然后就去网上搜,搜到了这么一篇文章 《Caffeine CacheManager 如何查看命中率、监控》 ,这篇文章是 2020 年的,距离现在已经快 4 年了,不知道是否正确,文章里面提到了需要重写 org.springframework.cache.caffeine.CaffeineCacheManager 对象。

我觉得重写的代码侵入太严重了,怕后期难维护,觉得可能还有其他的方法可以实现,然后就尝试去看 SpringBoot 源码,然后就找到了 CaffeineCacheManager 的配置方法。
1  | 
  | 
2. 定位问题
刚开始看到了这么一行代码 return customizers.customize(cacheManager); 在返回的时候用 CacheManagerCustomizers 去处理了 CaffeineCacheManager 对象,而它的实现如下:
1  | public class CacheManagerCustomizers {  | 
我以为只要自己实现一个 CacheManagerCustomizer 就可以处理 CaffeineCacheManager 对象从覆盖 org.springframework.cache.caffeine.CaffeineCacheManager#cacheBuilder 字段而开启统计功能,发现它是有这么一个方法,但是它是私有方法无法外部调用
1  | private void doSetCaffeine(Caffeine<Object, Object> cacheBuilder) {  | 
然后再发现 CaffeineCacheManager 有如下三个方法调用了这个私有方法:
1  | public void setCaffeine(Caffeine<Object, Object> caffeine) {  | 
随便选一个方法,用IDEA快捷键 Ctrl + Alt + F7 查看调用,最后发现回到了我们的 CaffeineCacheConfiguration 配置类里面有如下代码:
1  | private void setCacheBuilder(CacheProperties cacheProperties, CaffeineSpec caffeineSpec,  | 
然后选第一个设置方法 cacheManager.setCacheSpecification(specification); 进入到 CaffeineCacheManager 中发现
1  | public void setCacheSpecification(String cacheSpecification) {  | 
3. 解决问题
发现调用了 Caffeine.from(cacheSpecification) 这么一个方法,而这个方法里面又调用了 CaffeineSpec.parse(spec) 方法,最后点进去 CaffeineSpec 类里面一看,发现 CaffeineSpec 类顶部的注释有下面这些内容:

都是英文看不懂没关系,咱翻译一下

然后就发现有这么一行说明 recordStats : 设置 Caffeine.recordStats ,而 com.github.benmanes.caffeine.cache.Caffeine#recordStats() 方法就是启用统计功能用的方法,那是不是意味着只要在 String specification = cacheProperties.getCaffeine().getSpec(); 这个配置项里面配置 recordStats 就可以开启统计功能了?
那就开始尝试修改配置文件,加上 recordStats 参数
1  | spring:  | 
然后重启服务,再次查看我们的前端页面,发现统计功能已经生效了,数据不再是0了

因此在不改一行Java代码的情况下启用了缓存的统计功能。
不过我之前参考的文章是 2020 年的,过了 4 年时间,不确定这个配置是何时引入的,所以又去查看了一下 SpringBoot 的源码和 Caffeine 的源码,原来这个配置从一开始就已经存在了。
SpringBoot 的源码,关键代码行 8 年未变更 CaffeineCacheConfiguration.java#L72
Caffeine 的源码,关键说明内容 9 年未变更 CaffeineSpec.java#L50