package com.example.scaffold.cache; import com.github.benmanes.caffeine.cache.Caffeine; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; import java.util.concurrent.TimeUnit; /** * 缓存配置 - 支持 Caffeine(本地) 和 Redis(分布式) * * 学习要点: * 1. @EnableCaching - 启用 Spring Cache * 2. @Cacheable - 缓存方法结果 * 3. @CacheEvict - 清除缓存 * 4. @CachePut - 更新缓存 */ @Slf4j @Configuration @EnableCaching public class CacheConfig { /** * Caffeine 本地缓存 - 默认 */ @Bean @Primary @ConditionalOnProperty(name = "cache.type", havingValue = "caffeine", matchIfMissing = true) public CacheManager caffeineCacheManager() { log.info("🚀 启用 Caffeine 本地缓存"); CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder() // 初始容量 .initialCapacity(100) // 最大容量 .maximumSize(1000) // 写入后过期时间 .expireAfterWrite(10, TimeUnit.MINUTES) // 记录命中率 .recordStats() ); return cacheManager; } /** * Redis 分布式缓存 */ @Bean @ConditionalOnProperty(name = "cache.type", havingValue = "redis") public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) { log.info("🚀 启用 Redis 分布式缓存"); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() // 键序列化 .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(new StringRedisSerializer())) // 值序列化 .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(new GenericJackson2JsonRedisSerializer())) // 过期时间 .entryTtl(Duration.ofMinutes(10)) // 不缓存 null .disableCachingNullValues(); return RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .transactionAware() .build(); } /** * 自定义缓存 Key 生成器 */ @Bean public KeyGenerator customKeyGenerator() { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getSimpleName()).append(":"); sb.append(method.getName()).append(":"); for (Object param : params) { sb.append(param).append("-"); } return sb.toString(); }; } }