1. redis配置代码
package cn.doubi.learn.framework.redis.autoconfigure;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.math.BigDecimal;
import java.math.BigInteger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
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.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* 缓存配置-redis
* @Author liaoly
* @Date 2020年8月27日 下午2:20:34
*/
@Configuration
@EnableCaching
@ConditionalOnClass({RedisConnectionFactory.class})
@ConditionalOnProperty(prefix = "spring.redis",name = "host") //没有spring.redis.host 配置项时 不注入容器
@Slf4j
public class RedisConfiguration extends CachingConfigurerSupport {
/**
* Redis缓存配置:配置redisTemplate
* @author liaoly
* @date 2020年7月31日 下午2:22:45
* @return JedisPoolConfig
*/
@Bean
public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory factory) {
log.info("配置redisTemplate StringRedisTemplate");
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper());
redisTemplate.setConnectionFactory(factory);
//key序列化方式
redisTemplate.setKeySerializer(redisSerializer);
//value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
*
* Redis缓存配置:5.配置Redis缓存管理器: RedisCacheManager
*
* @author liaoly
* @date 2021年6月8日 上午11:02:47
* @param factory redis工厂
* @return CacheManager
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper());
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
return new TtlRedisCacheManager(RedisCacheWriter.lockingRedisCacheWriter(factory), config);
// return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
/**
* 全局的对象转化json规则自定义
* @return {@link ObjectMapper}
* @author liaoly
* @date 2022/6/27 10:02
*/
private ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
//将Long,BigInteger,BigDecimal序列化的时候,转化为String
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
objectMapper.registerModule(new JavaTimeModule());
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// 忽略未知字段
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance , ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// null值、""都不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return objectMapper;
}
/**
* 自定义缓存策略,对于同一业务(同一业务逻辑处理的方法,哪怕是集群/分布式系统),生成的 key 始终一致,对于不同业务则不一致:
*/
@Bean
public KeyGenerator customKeyGenerator() {
return (o, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}
2.自定义缓存管理器RedisCacheManager
package cn.doubi.learn.framework.redis.autoconfigure;
import java.time.Duration;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
*
* 自定义CacheManager, 解析 @Cacheable 支持设置缓存有效时间,写法如下:
* <code>@Cacheable(value = "AdminHome=24", key = "#root.methodName")</code> 代表缓存有效期24h
*
* value值单位:d:天;h:小时;m:分钟;s:秒(eg: 1d代表一天;2h代表2个小时;)
*
* @author liaoly(廖凌云) [1302013247@qq.com]
* @date 2022/9/13 15:36
*/
public class TtlRedisCacheManager extends RedisCacheManager {
//d:天;h:小时;m:分钟;s:秒
private static final String d = "d";
private static final String h = "h";
private static final String m = "m";
private static final String s = "s";
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
String[] cells = StringUtils.delimitedListToStringArray(name, "=");
name = cells[0].trim();
if (cells.length > 1) {
cacheConfig = entryTtl(cacheConfig, cells[1].trim().toLowerCase());
}
return super.createRedisCache(name, cacheConfig);
}
/**
* 根据传参设置缓存失效时间,并兼容单位(默认单位是h)
* @param cacheConfig redis缓存配置
* @param ttlStr 带单位的缓存有效期值 d:天;h:小时;m:分钟;s:秒(eg: 1d代表一天;2h代表2个小时;)
* @return {@link RedisCacheConfiguration}
* @author liaoly
* @date 2023/3/24 8:20
*/
private RedisCacheConfiguration entryTtl(RedisCacheConfiguration cacheConfig, String ttlStr) {
ttlStr = ttlStr.toLowerCase();
if (ttlStr.endsWith(d)) {
return cacheConfig.entryTtl(Duration.ofDays(Long.parseLong(ttlStr.replace(d, ""))));
} else if (ttlStr.endsWith(h)) {
return cacheConfig.entryTtl(Duration.ofHours(Long.parseLong(ttlStr.replace(h, ""))));
} else if (ttlStr.endsWith(m)) {
return cacheConfig.entryTtl(Duration.ofMinutes(Long.parseLong(ttlStr.replace(m, ""))));
} else if (ttlStr.endsWith(s)) {
return cacheConfig.entryTtl(Duration.ofSeconds(Long.parseLong(ttlStr.replace(s, ""))));
} else {
return cacheConfig.entryTtl(Duration.ofHours(Long.parseLong(ttlStr.replaceAll("[^\\d]", ""))));
}
}
}