Spring Boot缓存优化:@Cacheable高级应用与性能调优

缓存基础配置与常规实践

1. 注解参数全解析

@Cacheable(value = "userProfile", 
           key = "#userId + '_' + #type",
           condition = "#userId.startsWith('VIP')",
           unless = "#result == null || #result.isDisabled()")
public UserProfile getUserProfile(String userId, String type) {
    // 数据库查询逻辑
}
  • value/cacheNames:定义逻辑缓存分区,支持多缓存声明
  • key:SpEL表达式构建复合键,建议使用参数组合表达式
  • condition:前置条件判断,满足条件才执行缓存
  • unless:后置结果判断,否决缓存写入

2. 缓存管理器选型

spring:
  cache:
    type: redis
    redis:
      time-to-live: 30m
      cache-null-values: true
      key-prefix: APP_CACHE_
      use-key-prefix: true
    caffeine:
      spec: maximumSize=500,expireAfterWrite=10m

多级缓存组合配置示例:

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisCacheConfiguration redisConfig = RedisCacheConfiguration.defaultCacheConfig()
        .serializeValuesWith(RedisSerializationContext.SerializationPair
            .fromSerializer(new GenericJackson2JsonRedisSerializer()));
    
    CaffeineCacheManager localCacheManager = new CaffeineCacheManager();
    localCacheManager.setCaffeine(Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(5, TimeUnit.MINUTES));
    
    return new CompositeCacheManager(localCacheManager, 
        RedisCacheManager.builder(factory).cacheDefaults(redisConfig).build());
}

高级缓存策略实现

3. 防缓存穿透方案

@Cacheable(value = "productDetail", 
           unless = "#result == null")
public Product getProductDetail(Long productId) {
    Product product = productDao.getById(productId);
    if (product == null) {
        // 记录异常访问日志
        auditService.recordInvalidQuery(productId);
        // 返回特殊空对象
        return Product.EMPTY;
    }
    return product;
}

4. 缓存预热机制

@Scheduled(fixedRate = 30_000)
@CacheEvict(value = "hotProducts", allEntries = true)
public void preloadHotProducts() {
    List<Product> products = productService.getTop100HotProducts();
    products.parallelStream().forEach(p -> {
        cacheManager.getCache("hotProducts")
            .put(p.getId(), p);
    });
}

性能优化实战技巧

5. 序列化优化配置

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(factory);
    
    Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(
        new ObjectMapper().registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false),
        Object.class
    );
    
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(serializer);
    template.setHashKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(serializer);
    return template;
}

6. 并发控制优化

@Cacheable(value = "inventory", 
           key = "#productId",
           sync = true)
public Integer getProductInventory(Long productId) {
    return inventoryService.getRealTimeInventory(productId);
}

监控与诊断方案

7. 缓存命中率监控

@Aspect
@Component
@Slf4j
public class CacheMonitorAspect {
    
    @Autowired
    private CacheMetricsCollector metricsCollector;

    @Around("@annotation(org.springframework.cache.annotation.Cacheable)")
    public Object monitorCache(ProceedingJoinPoint joinPoint) throws Throwable {
        String cacheName = ((Cacheable) ((MethodSignature) joinPoint.getSignature())
            .getMethod().getAnnotation(Cacheable.class)).value()[0];
        
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long duration = System.currentTimeMillis() - start;
        
        metricsCollector.recordCacheAccess(cacheName, duration, result != null);
        return result;
    }
}

典型问题解决方案

8. 缓存数据版本控制

@Cacheable(value = "userConfig", 
           key = "#userId",
           cacheResolver = "versionAwareCacheResolver")
public UserConfig getUserConfig(String userId) {
    return configService.getLatestConfig(userId);
}

@Bean
public CacheResolver versionAwareCacheResolver() {
    return new CacheResolver() {
        @Override
        public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
            String version = configService.getCurrentSchemaVersion();
            String cacheName = context.getOperation().getCacheNames().iterator().next() + "_v" + version;
            return Collections.singleton(cacheManager.getCache(cacheName));
        }
    };
}

9. 大Value分块缓存

@Cacheable(value = "largeReport", 
           key = "#reportId")
public Report getLargeReport(String reportId) {
    Report report = reportService.generateReport(reportId);
    // 分块存储附加数据
    cacheManager.getCache("reportChunks")
        .put(reportId + "_attachments", 
             splitAttachments(report.getAttachments()));
    return report.withoutAttachments();
}

调试与问题排查

10. 缓存追踪日志

logging.level.org.springframework.cache=TRACE
logging.level.net.sf.ehcache=DEBUG
logging.level.com.github.benmanes.caffeine=DEBUG

诊断日志分析要点:

  • Cache miss/hit 日志模式识别
  • 序列化异常堆栈跟踪
  • 缓存淘汰策略执行记录
  • Redis连接池状态监控
正文到此结束
评论插件初始化中...
Loading...