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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:42:35