Spring Cache缓存注解深度解析
一、框架概述
Spring Cache是Spring框架提供的抽象缓存层,通过注解实现声明式缓存,与具体缓存实现(如Redis、Ehcache)解耦。核心接口CacheManager
负责管理不同缓存,@EnableCaching
开启注解驱动。
二、核心注解详解
1. @Cacheable
- 作用:方法结果缓存,首次调用后缓存结果
- 关键参数:
@Cacheable( value = "userCache", key = "#userId + ':' + #type.code", // SpEL动态键 condition = "#userId.startsWith('A')", // 前置条件 unless = "#result.age < 18", // 结果过滤 sync = true // 并发锁(防击穿) ) public User getUser(String userId, UserType type) { ... }
- 执行流程:
- 根据key检查缓存是否存在
- 命中缓存直接返回
- 未命中执行方法体,按条件存储结果
2. @CachePut
- 强制更新缓存:每次执行方法后更新缓存
@CachePut(value = "userCache", key = "#user.id") public User updateUser(User user) { // 更新数据库 return user; // 返回值作为新缓存 }
3. @CacheEvict
- 缓存清除策略:
@CacheEvict( value = {"userCache", "orderCache"}, key = "#userId", allEntries = false, // 是否清空整个缓存区域 beforeInvocation = true // 在方法执行前清除(防失败残留) ) public void deleteUser(String userId) { ... }
4. 复合注解@Caching
- 多操作组合:
@Caching( cacheable = @Cacheable(value = "tempCache", key = "#id"), evict = @CacheEvict(value = "mainCache", key = "#id") ) public Data complexOperation(Long id) { ... }
5. 类级@CacheConfig
- 共享公共配置:
@CacheConfig(cacheNames = "orders", keyGenerator = "customKeyGen") @Service public class OrderService { @Cacheable // 继承类级别的orders缓存配置 public Order getOrder(Long id) { ... } }
三、高级配置技巧
1. 自定义Key生成器
实现KeyGenerator
接口:
@Bean
public KeyGenerator businessKeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getSimpleName());
sb.append(method.getName());
Arrays.stream(params).forEach(p -> sb.append(p.toString()));
return sb.toString();
};
}
// 使用
@Cacheable(value="reports", keyGenerator="businessKeyGenerator")
2. Redis序列化优化
配置Jackson2序列化器:
@Bean
public RedisCacheConfiguration cacheConfig() {
return RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues();
}
3. 多缓存管理器
多Redis实例配置:
@Primary
@Bean
public CacheManager redisCacheManager(RedisConnectionFactory factory) {
// 主缓存配置
}
@Bean
public CacheManager redisTempCacheManager(RedisConnectionFactory factory) {
// 临时缓存专用配置
}
// 使用指定管理器
@Cacheable(value = "tempData", cacheManager = "redisTempCacheManager")
四、实践场景示例
1. 防雪崩策略
// 随机过期时间分散风险
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.builder(factory)
.cacheDefaults(cacheConfig().entryTtl(Duration.ofMinutes(30)))
.withInitialCacheConfigurations(
Map.of("productCache",
cacheConfig().entryTtl(Duration.ofSeconds(1800 + new Random().nextInt(300)))
)
).build();
}
2. 缓存穿透防护
@Cacheable(value = "products", unless = "#result == null")
public Product getProduct(Long id) {
Product p = db.query(id);
if(p == null) {
return new NullProduct(); // 特殊空对象
}
return p;
}
3. 热点数据永不过期+后台刷新
@Scheduled(fixedRate = 3600000)
@CachePut(value = "hotData", key = "'top10'")
public List<Data> refreshHotData() {
return db.getTop10(); // 定时刷新
}
五、调试与监控
-
日志追踪:
properties
logging.level.org.springframework.cache=TRACE
-
指标监控:
// 通过Micrometer暴露缓存指标 @Autowired private CacheMetricsProvider metricsProvider; public void monitor() { Cache cache = cacheManager.getCache("userCache"); metricsProvider.getCacheMetrics(cache).forEach((k,v) -> { System.out.println(k + ": " + v); }); }
-
可视化工具:
- RedisInsight:查看Redis存储结构
- Spring Boot Actuator:/actuator/caches端点
六、常见问题解决
-
自调用失效:
// 错误示例 public void update(User user) { this.innerUpdate(user); // 自调用不走代理 } @CacheEvict(value="users", key="#user.id") private void innerUpdate(User user) { ... } // 解决方案:通过AopContext获取代理对象 @EnableAspectJAutoProxy(exposeProxy = true) public class AppConfig {} ((UserService) AopContext.currentProxy()).innerUpdate(user);
-
并发更新问题:
@Cacheable(value = "locks", key = "#key", sync = true) public String getWithLock(String key) { // 同步代码块 }
-
缓存与DB一致性:
@Transactional @CacheEvict(value = "orders", key = "#order.id") public void updateOrder(Order order) { // 先更新数据库,事务提交后清除缓存 }
七、性能优化建议
-
批量操作:
@Cacheable(value = "users") public Map<Long, User> batchGetUsers(Set<Long> ids) { // 返回Map结构,利用Redis MGET批量获取 }
-
分级缓存策略:
@Caching(cacheable = { @Cacheable(value = "localCache", key = "#id"), @Cacheable(value = "redisCache", key = "#id") }) public Data getMultiLevel(Long id) { ... }
-
异步加载:
@Async @Cacheable(value = "asyncCache", key = "#id") public CompletableFuture<Data> asyncGetData(Long id) { ... }
通过深度掌握Spring Cache注解机制,开发者可以构建高效可靠的缓存体系。建议结合具体业务场景灵活选择注解组合,配合Redis的丰富数据结构实现最优性能。