1.在此之前当我们在pom.xml dependencies 中引入redis starter依赖
<dependencies>
<!--Redis 缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
配置文件配置
Spring:
redis:
host: 47.103.179.88
port: 6379
password: Redis123456
max-wait: 30000 #连接池最大阻塞等待时间(使用负值表示没有限制)
max-active: 100 #连接池最大连接数(使用负值表示没有限制)
max-idle: 20 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
timeout: 3000 #连接超时
RedisConfig.java配置类
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* retemplate相关配置
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 设置CacheManager的值序列化方式为Jackson2JsonRedisSerializer,默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
// 配置value序列化方式为Jackson2JsonRedisSerializer,key序列化方式采用默认的StringRedisSerializer
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofDays(1L));
// 初始化RedisCacheManager
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
return cacheManager;
}
}
注意 cacheManager方法中.entryTtl(Duration.ofDays(1L)); 不能用defaultCacheConfig.entryTtl(Duration.ofDays(1L));只能按上面代码中这样写,objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);这个也是必要的当reids库中字段多了可以自动不解析并且不会抛异常
在方法上添加缓存注解
@Service
public class CacheService {
// 添加缓存 ,下次再执行这个方法就从redis缓存中取数据
//value 是指定业务名称,必须有,key是缓存key的名称 #name 表示是参数的name
//key = "#p0" 代表此方法的第一个参数
@Cacheable(value = "names", key = "'names:' + #name")
public Hello hello(String name) {
return hello;
}
//更新缓存 ,每次都会执行,更新数据到缓存中
@CachePut(value = "names", key = "'names:' + #name")
public Hello update(String name) {
return hello;
}
//删除缓存
@CacheEvict(value = "names", key = "'names:' + #name")
public Hello delete(String name) {
return hello;
}
还有其他参数需要百度【比如插入缓存的条件等】
---------------------------------------------------------------------------------------------------------------------
设置不同的 过期时间
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* retemplate相关配置
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(1L),
this.getRedisCacheConfigurationMap()
);
}
/**
* 指定 key 策略
* @return Map<String, RedisCacheConfiguration>
*/
private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = Maps.newHashMap();
//进行过期时间配置
redisCacheConfigurationMap.put("BasicDataCacheForever", this.getRedisCacheConfigurationWithTtl(-1L));
return redisCacheConfigurationMap;
}
/**
* 默认策略,未配置的 key 会使用这个
* @param day 过期时间 1 为 1天 -1为无过期时间
* @return
*/
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(long day) {
// 设置CacheManager的值序列化方式为Jackson2JsonRedisSerializer,默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 配置value序列化方式为Jackson2JsonRedisSerializer,key序列化方式采用默认的StringRedisSerializer
RedisCacheConfiguration defaultCacheConfig;
if(day > 0){
defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofDays(day));
}else {
defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
}
return defaultCacheConfig;
}
// @Bean
// public KeyGenerator wiselyKeyGenerator() {
// return (target, method, params) -> {
// StringBuilder sb = new StringBuilder();
// sb.append(target.getClass().getName());
// sb.append("." + method.getName());
// if(params==null||params.length==0||params[0]==null){
// return null;
// }
// String join = String.join("&", Arrays.stream(params).map(Object::toString).collect(Collectors.toList()));
// String format = String.format("%s{%s}", sb.toString(), join);
// return format;
// };
// }
}
注意:
spring cache 的原理是 基于动态生成的proxy代理机制来对方法的调用进行切面,如果对象的方法是 内部调用而不是外部引用,则会导致proxy失效,也就是说 @cacheable @cachePut@cacheEvict都会失效
解决方法
1.可以把removeGroupUserStatusCached方法单独抽取到另外一个类里面,通过代理类引入。
2.通过((GroupUserService)AopContext.currentProxy()).removeGroupUserStatusCached方法获取当前类的代理类;
3.通过ApplicationContext获取当前类的代理对象,GroupUserService groupUserService = springContextUtil.getBean(GroupUserService.class);
学习地址:
https://www.freesion.com/article/471336913/