refactor(cache): 纵深防御与风格清理(autoType/锁key/抖动上界/key校验/proxyBeanMethods)

- CacheValueCodec.decode 关闭 fastjson @type 自动类型(Feature.IgnoreAutoType):
  纵深防御;经验证常规链路本已安全(指定目标类型时 @type 被忽略),此为显式锁定契约。
- 模板锁 key 改用 keyBuilder.buildLock(key),与 CacheKeyBuilder 单一来源,消除重复派生。
- applyJitter 上界改 nextLong(bound) 对齐 spec 半开区间 [ttl, ttl*(1+ratio));测试收紧为严格 <。
- CacheKeyBuilder.build 对空白 bizKey fail-fast,避免 "cache:null" 静默键碰撞。
- RedisCacheAutoConfiguration 用 @Configuration(proxyBeanMethods=false),省 CGLIB 代理开销。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-06-26 10:08:56 +08:00
parent 6a4f5e460e
commit 24422d0ce4
7 changed files with 32 additions and 10 deletions

View File

@@ -118,7 +118,7 @@ public class RedisCacheEnhanceTemplate {
}
}
/** 在原 TTL 上叠加 [0, ttl*ratio] 的随机抖动(只增不减);ratio<=0 或 ttl<=0 时原样返回。 */
/** 在原 TTL 上叠加 [0, ttl*ratio) 的随机抖动(只增不减,半开区间);ratio<=0 或 ttl<=0 时原样返回。 */
long applyJitter(long ttlSeconds) {
double ratio = props.getJitterRatio();
if (ratio <= 0 || ttlSeconds <= 0) {
@@ -128,7 +128,7 @@ public class RedisCacheEnhanceTemplate {
if (bound <= 0) {
return ttlSeconds;
}
return ttlSeconds + ThreadLocalRandom.current().nextLong(bound + 1);
return ttlSeconds + ThreadLocalRandom.current().nextLong(bound);
}
/** TTL 必须为正:0/负会被 Redis 当作"立即删除"(EXPIRE)或非法过期时间(SET),显式 fail-fast。 */
@@ -202,7 +202,7 @@ public class RedisCacheEnhanceTemplate {
return loadAndCache(dataKey, ttlSeconds, loader);
}
String lockKey = dataKey + CacheConstant.LOCK_SUFFIX;
String lockKey = keyBuilder.buildLock(key); // 复用 keyBuilder,锁 key 规则单一来源
String token = IdUtil.fastSimpleUUID();
boolean locked = Boolean.TRUE.equals(redis.opsForValue()
.setIfAbsent(lockKey, token, Duration.ofMillis(bd.getLockTtlMs())));