Spring Cache缓存注解深度解析

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) { ... }
  • 执行流程
    1. 根据key检查缓存是否存在
    2. 命中缓存直接返回
    3. 未命中执行方法体,按条件存储结果
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();  // 定时刷新
}
五、调试与监控
  1. 日志追踪

    properties

    logging.level.org.springframework.cache=TRACE
  2. 指标监控

    // 通过Micrometer暴露缓存指标
    @Autowired
    private CacheMetricsProvider metricsProvider;
    
    public void monitor() {
        Cache cache = cacheManager.getCache("userCache");
        metricsProvider.getCacheMetrics(cache).forEach((k,v) -> {
            System.out.println(k + ": " + v);
        });
    }
  3. 可视化工具

    • RedisInsight:查看Redis存储结构
    • Spring Boot Actuator:/actuator/caches端点
六、常见问题解决
  1. 自调用失效

    // 错误示例
    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);
  2. 并发更新问题

    @Cacheable(value = "locks", key = "#key", sync = true)
    public String getWithLock(String key) {
        // 同步代码块
    }
  3. 缓存与DB一致性

    @Transactional
    @CacheEvict(value = "orders", key = "#order.id")
    public void updateOrder(Order order) {
        // 先更新数据库,事务提交后清除缓存
    }
七、性能优化建议
  1. 批量操作

    @Cacheable(value = "users")
    public Map<Long, User> batchGetUsers(Set<Long> ids) {
        // 返回Map结构,利用Redis MGET批量获取
    }
  2. 分级缓存策略

    @Caching(cacheable = {
        @Cacheable(value = "localCache", key = "#id"),
        @Cacheable(value = "redisCache", key = "#id")
    })
    public Data getMultiLevel(Long id) { ... }
  3. 异步加载

    @Async
    @Cacheable(value = "asyncCache", key = "#id")
    public CompletableFuture<Data> asyncGetData(Long id) { ... }

通过深度掌握Spring Cache注解机制,开发者可以构建高效可靠的缓存体系。建议结合具体业务场景灵活选择注解组合,配合Redis的丰富数据结构实现最优性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值