如何为Caffeine Cache单条目设动态TTL?Policy为空问题求解
问题根源
你现在的Caffeine缓存用了expireAfterWrite固定过期策略,这种配置下缓存不支持可变过期(Variable Expiration),所以调用nativeCache.policy().expireVariably()会返回空的Optional,直接get()就会触发空指针异常。
解决办法
1. 调整Caffeine配置,开启可变过期支持
必须修改你的Caffeine Bean配置,把固定过期换成支持可变过期的配置,两种可选方式:
方式一:直接开启可变过期
如果不需要默认过期时长,直接用这个配置:
@Bean public Caffeine CaffeineCacheConfig() { return Caffeine.newBuilder() .expireVariably() // 核心:开启可变过期支持 .initialCapacity(1000) .maximumSize(1200); }
方式二:保留默认过期+支持自定义
要是想给大部分缓存条目留个默认过期时间,同时允许个别条目自定义过期时长,就用自定义Expiry的方式:
@Bean public Caffeine CaffeineCacheConfig() { return Caffeine.newBuilder() .expireAfter(new Expiry<Object, Object>() { @Override public long expireAfterCreate(Object key, Object value, long currentTime) { // 默认创建后5分钟过期,和你原配置一致 return TimeUnit.MINUTES.toNanos(5); } @Override public long expireAfterUpdate(Object key, Object value, long currentTime, long currentDuration) { // 更新后沿用剩余过期时长,可按需修改 return currentDuration; } @Override public long expireAfterRead(Object key, Object value, long currentTime, long currentDuration) { // 读取后沿用剩余过期时长,可按需修改 return currentDuration; } }) .initialCapacity(1000) .maximumSize(1200); }
这种方式下,缓存既有默认过期规则,也能通过VarExpiration接口单独修改某条缓存的过期时间。
2. 给业务方法加空指针防护
就算配置正确,也建议给Optional做非空判断,避免意外报错:
@Override public void addObjectToCacheWithExpiry(CaffeineCacheManager caffeineCacheManager, String cacheName, String key, Object value, long duration, TimeUnit timeUnit) { CaffeineCache caffeineCache = (CaffeineCache) caffeineCacheManager.getCache(cacheName); if (caffeineCache == null) { throw new IllegalArgumentException("缓存[" + cacheName + "]不存在"); } Cache<Object, Object> nativeCache = caffeineCache.getNativeCache(); // 用ifPresent避免空指针 nativeCache.policy().expireVariably().ifPresent(varExpiration -> { varExpiration.put(key, value, duration, timeUnit); }); }
重要提示
- 只有当缓存构建时配置了
expireVariably()或者自定义Expiry实现,policy().expireVariably()才会返回非空的结果。 - 若同时配置了固定过期(如
expireAfterWrite)和可变过期,固定策略会被覆盖,缓存将完全遵循可变过期规则。
内容的提问来源于stack exchange,提问作者xyz
相关产品推荐
相关产品推荐

