package com.oying.config;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONFactory;
|
import com.alibaba.fastjson2.JSONWriter;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.codec.digest.MurmurHash3;
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
import org.springframework.cache.Cache;
|
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
import org.springframework.cache.annotation.EnableCaching;
|
import org.springframework.cache.interceptor.CacheErrorHandler;
|
import org.springframework.cache.interceptor.KeyGenerator;
|
import org.springframework.cache.interceptor.SimpleCacheErrorHandler;
|
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Configuration;
|
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.core.RedisTemplate;
|
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
import org.springframework.data.redis.serializer.SerializationException;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import java.nio.charset.StandardCharsets;
|
import java.time.Duration;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* @author Z
|
* @date 2025-01-13
|
*/
|
@Slf4j
|
@Configuration
|
@EnableCaching
|
@AutoConfigureBefore(RedisAutoConfiguration.class)
|
public class RedisConfiguration extends CachingConfigurerSupport {
|
|
// 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
|
private static final String[] WHITELIST_STR = {"com.oying" };
|
|
/**
|
* 设置 redis 数据默认过期时间,默认2小时
|
* 设置@cacheable 序列化方式
|
*/
|
@Bean
|
public RedisCacheConfiguration redisCacheConfiguration(){
|
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
configuration = configuration.serializeValuesWith(RedisSerializationContext.
|
SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2));
|
return configuration;
|
}
|
|
@Bean(name = "redisTemplate")
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
// 指定 key 和 value 的序列化方案
|
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
// value值的序列化采用fastJsonRedisSerializer
|
template.setValueSerializer(fastJsonRedisSerializer);
|
template.setHashValueSerializer(fastJsonRedisSerializer);
|
// 设置fastJson的序列化白名单
|
for (String pack : WHITELIST_STR) {
|
JSONFactory.getDefaultObjectReaderProvider().addAutoTypeAccept(pack);
|
}
|
// key的序列化采用StringRedisSerializer
|
template.setKeySerializer(new StringRedisSerializer());
|
template.setHashKeySerializer(new StringRedisSerializer());
|
template.setConnectionFactory(redisConnectionFactory);
|
return template;
|
}
|
|
/**
|
* 缓存管理器
|
* @param redisConnectionFactory /
|
* @return 缓存管理器
|
*/
|
@Bean
|
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
|
RedisCacheConfiguration config = redisCacheConfiguration();
|
return RedisCacheManager.builder(redisConnectionFactory)
|
.cacheDefaults(config)
|
.build();
|
}
|
|
/**
|
* 自定义缓存key生成策略
|
*/
|
@Bean
|
public KeyGenerator keyGenerator() {
|
return (target, method, params) -> {
|
Map<String,Object> container = new HashMap<>(8);
|
Class<?> targetClassClass = target.getClass();
|
// 类地址
|
container.put("class",targetClassClass.toGenericString());
|
// 方法名称
|
container.put("methodName",method.getName());
|
// 包名称
|
container.put("package",targetClassClass.getPackage());
|
// 参数列表
|
for (int i = 0; i < params.length; i++) {
|
container.put(String.valueOf(i),params[i]);
|
}
|
// 转为JSON字符串
|
String jsonString = JSON.toJSONString(container);
|
// 使用 MurmurHash 生成 hash
|
return Integer.toHexString(MurmurHash3.hash32x86(jsonString.getBytes()));
|
};
|
}
|
|
@Bean
|
@SuppressWarnings({"unchecked","all"})
|
public CacheErrorHandler errorHandler() {
|
return new SimpleCacheErrorHandler() {
|
@Override
|
public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
|
// 处理缓存读取错误
|
log.error("Cache Get Error: {}",exception.getMessage());
|
}
|
@Override
|
public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
|
// 处理缓存写入错误
|
log.error("Cache Put Error: {}",exception.getMessage());
|
}
|
@Override
|
public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
|
// 处理缓存删除错误
|
log.error("Cache Evict Error: {}",exception.getMessage());
|
}
|
@Override
|
public void handleCacheClearError(RuntimeException exception, Cache cache) {
|
// 处理缓存清除错误
|
log.error("Cache Clear Error: {}",exception.getMessage());
|
}
|
};
|
}
|
|
/**
|
* Value 序列化
|
*
|
* @param <T>
|
* @author Z
|
*/
|
static class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
|
private final Class<T> clazz;
|
|
FastJsonRedisSerializer(Class<T> clazz) {
|
super();
|
this.clazz = clazz;
|
}
|
|
@Override
|
public byte[] serialize(T t) throws SerializationException
|
{
|
if (t == null) {
|
return new byte[0];
|
}
|
return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(StandardCharsets.UTF_8);
|
}
|
|
@Override
|
public T deserialize(byte[] bytes) throws SerializationException
|
{
|
if (bytes == null || bytes.length == 0) {
|
return null;
|
}
|
String str = new String(bytes, StandardCharsets.UTF_8);
|
return JSON.parseObject(str, clazz);
|
}
|
|
}
|
}
|