spring cache通过@cacheable、@cacheevict等注解实现声明式缓存,需配合redis配置使用;@cacheable先查缓存后回源,@cacheevict精准清理缓存,二者均依赖@enablecaching开启及合理key设计,且受限于代理aop机制。

Spring 通过 @Cacheable、@CacheEvict 等注解把缓存逻辑从代码中剥离出来,配合 Redis 作为底层缓存存储,能显著减少手动操作 Redis 的重复工作。关键不是“加注解就完事”,而是配对配置、理解缓存键生成规则、注意方法执行时机和缓存一致性边界。
启用缓存并接入 Redis
先确保项目已引入 spring-boot-starter-cache 和 spring-boot-starter-data-redis,然后在启动类或配置类上加 @EnableCaching 开启缓存支持。
默认情况下 Spring Cache 抽象不直接使用 Redis —— 需要显式配置 RedisCacheManager(Spring Boot 2.5+ 推荐用 RedisCacheConfiguration 自定义序列化):
- 设置 key 序列化为
StringRedisSerializer,避免乱码 - 设置 value 序列化为
GenericJackson2JsonRedisSerializer或Jackson2JsonRedisSerializer,保证对象可读、兼容性好 - 可按业务划分 cache 名称(如
"user"、"order"),并在注解中指定
@Cacheable:自动读缓存 + 回源写缓存
标注在方法上,表示“先查缓存,命中则返回;未命中则执行方法,结果存入缓存再返回”。它不关心方法是否已有数据,只管“缓存是否存在 + 是否过期”。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
常用写法示例:
@Cacheable(value = "user", key = "#id")
public User findById(Long id) {
return userMapper.selectById(id); // 实际查库
}
-
value对应缓存名(即 Redis 中的 cache prefix),实际 key 是cacheName:generatedKey -
key支持 SpEL 表达式:#id取参数值,#root.args[0]取第一个参数,#result在unless中可用 -
unless = "#result == null"可防止空对象被缓存;condition = "#id > 0"控制哪些调用才走缓存
@CacheEvict:精准清理缓存,避免脏数据
用于删除缓存,常见于增删改操作后。它不执行方法体,只负责“清掉对应缓存项”。
-
@CacheEvict(value = "user", key = "#id"):删除单个 key -
@CacheEvict(value = "user", allEntries = true):清空整个 user 缓存区域(慎用,影响面大) -
@CacheEvict(value = "user", key = "#user.id", beforeInvocation = true):设为true表示方法执行前就清缓存(适合更新前确保旧缓存失效) - 若方法可能抛异常,且希望异常时也清缓存,必须设
beforeInvocation = true,否则默认仅成功后执行
几个容易踩的坑
缓存注解是基于代理的 AOP 实现,因此有天然限制:
- 不能在同一个类的内部方法调用中标注缓存注解(私有方法、this.调用均无效)
- 被注解的方法必须是 public,且不能是 final 或 static
- 如果参数对象没重写
hashCode()和equals(),默认 key 生成可能出错(建议用简单类型或 String 做 key) - 缓存穿透/击穿/雪崩需额外防护(如布隆过滤器、逻辑过期、互斥锁),注解本身不提供这些能力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










