100 lines
3.6 KiB
Java
100 lines
3.6 KiB
Java
|
|
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();
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|