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 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 redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate template = new RedisTemplate<>(); // 指定 key 和 value 的序列化方案 FastJsonRedisSerializer 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 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 * @author Z */ static class FastJsonRedisSerializer implements RedisSerializer { private final Class clazz; FastJsonRedisSerializer(Class 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); } } }