Spring Boot 1.5.12+Caffeine同步缓存@Cacheable(sync=true)失效问题
解决Spring Boot 1.5.x + Caffeine下@Cacheable sync=true不生效的问题
根据你描述的场景——用@Cacheable(sync = true)期望并发调用时只有一个线程执行方法,但实际日志重复输出,同步缓存未生效——大概率是以下几个核心原因导致的,我们一步步排查解决:
1. 缓存Key生成不一致(最常见诱因)
@Cacheable的同步机制完全依赖相同参数生成完全一致的缓存Key,如果Key不同,每个调用都会被判定为新的缓存条目,自然不会触发同步等待逻辑。
你的方法参数包含OffsetDateTime,Spring默认的SimpleKeyGenerator会直接用对象的equals和hashCode生成Key,但这里容易踩两个坑:
OffsetDateTime的时区差异:两个代表同一时刻但时区不同的实例,equals会返回false,导致Key完全不同- 对象序列化细节:
OffsetDateTime的toString输出可能包含纳秒、时区标识等可变内容,也会导致Key不一致
解决办法:自定义Key生成器
创建一个自定义Key生成器,把OffsetDateTime转换为时间戳(忽略时区,只保留核心时刻信息):
import org.springframework.cache.interceptor.KeyGenerator import org.springframework.stereotype.Component import java.lang.reflect.Method import java.time.OffsetDateTime @Component class CustomCacheKeyGenerator : KeyGenerator { override fun generate(target: Any, method: Method, vararg params: Any): Any { val keySegments = params.map { param -> when (param) { is OffsetDateTime -> param.toInstant().toEpochMilli().toString() else -> param.toString() } } val key = keySegments.joinToString("-") // 可选:打印生成的Key,验证相同参数是否生成一致结果 // LOGGER.debug("Generated cache key for ${method.name}: $key") return key } }
然后在@Cacheable注解中指定这个生成器:
@Cacheable( cacheNames = [CacheService.MY_CACHE_NAME], sync = true, keyGenerator = "customCacheKeyGenerator" ) fun fetchThing(id: Int, at: OffsetDateTime?): Thing? { // 方法逻辑... }
2. Caffeine未配置允许Null值
你的方法返回Thing?(可能返回null),而Caffeine默认禁止缓存Null值。如果方法返回null,缓存不会存储任何条目,后续调用仍会执行方法,看起来同步机制失效。
解决办法:配置Caffeine允许Null值
方式1:Kotlin配置类
import com.github.benmanes.caffeine.cache.Caffeine import org.springframework.cache.CacheManager import org.springframework.cache.caffeine.CaffeineCacheManager import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import java.util.concurrent.TimeUnit @Configuration class CacheConfig { @Bean fun cacheManager(): CacheManager { val caffeineConfig = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) .allowNullValues() // 关键:开启Null值缓存支持 return CaffeineCacheManager().apply { setCaffeine(caffeineConfig) } } }
方式2:application.properties配置
spring.cache.type=caffeine spring.cache.caffeine.spec=maximumSize=1000,expireAfterWrite=10m,allowNullValues
3. 验证Spring Cache与Caffeine的集成正确性
Spring Boot 1.5.12默认会自动配置CaffeineCacheManager,但如果你的项目中有自定义的CacheManager Bean,可能覆盖了默认配置,导致同步逻辑失效。
快速验证:
- 检查项目中是否存在自定义
CacheManager,确保它是基于Caffeine实现的 - 确认项目依赖中只引入了Caffeine相关依赖,没有同时引入其他缓存提供者(如Ehcache)导致冲突
4. 开启日志排查细节
如果以上步骤都无法解决问题,可以开启Spring Cache的DEBUG日志,查看缓存查找、存储的完整流程:
logging.level.org.springframework.cache=DEBUG
通过日志可以清晰看到每个调用的Key生成、缓存命中情况,进一步定位问题根源。
内容的提问来源于stack exchange,提问作者andrew
相关产品推荐
相关产品推荐

