用自定义注解+ AOP 实现二级缓存自动同步,通过 @TwoLevelCache 和 @TwoLevelCacheEvict 声明缓存意图,切面统一执行“本地→远程→DB”读流程与事务后原子失效,并借助 Redisson Pub/Sub 保证多节点一致性。

用自定义注解 + AOP 实现二级缓存自动同步,核心是把缓存读写、失效、一致性保障这些逻辑从业务代码里彻底剥离,靠注解声明意图,靠切面统一执行。不是简单加个缓存,而是让 Caffeine(本地)和 Redis(远程)协同工作,并在更新时保证多节点间数据一致。
定义分层缓存专用注解
不复用 Spring Cache 的 @Cacheable,而是设计语义更明确的注解:
- @TwoLevelCache:用于查询方法,指定缓存名、key 表达式(如 "#id")、过期时间;支持 SpEL 解析参数生成动态 key
- @TwoLevelCacheEvict:用于更新/删除方法,声明需失效的缓存名与 key,支持批量失效(如 {"user:#id", "profile:#id"})
- 可选增加 @CacheLock 注解,自动触发 Redis 分布式锁,防止缓存击穿或并发更新冲突
切面中实现“先本地、再远程、最后 DB”的读流程
环绕通知按顺序检查:
- 先查 Caffeine:命中则直接返回,避免网络开销
- 未命中则查 Redis:命中则写回 Caffeine 并返回(形成“回写”)
- Redis 也未命中才执行原方法,结果同时写入 Redis 和 Caffeine
- 对空结果做特殊标记(如存空对象或 null 字符串),防缓存穿透
写操作触发原子性失效与集群同步
更新类方法执行后,必须确保缓存及时、准确、安全地清理:
- 事务提交成功后才触发失效——通过 TransactionSynchronizationManager.registerSynchronization() 延迟到 commit 阶段执行,避免回滚导致脏缓存
- Redis 失效用 Lua 脚本执行,保证多 key 删除的原子性(例如:DEL key1 key2 key3)
- 失效后立即通过 Redisson Pub/Sub 发布消息(如 channel:cache-evict:user:1001),所有服务节点订阅并清除对应 Caffeine 条目
- MyBatis 拦截器自动为 @Update/@Delete 方法追加 FOR UPDATE,配合数据库行级锁,防止并发更新引发中间态读取
零侵入封装与运行时可控性
真正做到业务无感,同时保留调试与降级能力:
- 所有缓存行为由注解驱动,方法体里不出现任何 redisTemplate 或 cache.get() 调用
- 支持运行时开关:通过配置项(如 cache.enabled=false)一键关闭整个二级缓存链路,切面直接放行原逻辑
- 关键路径打日志(如“Caffeine miss → Redis hit → load from DB”),便于线上问题定位
- 缓存 key 生成策略统一管理,避免各处手拼 key 导致不一致
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











