pom文件添加如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
配置appliation.yml文件
我这里配置的是集群,单机就配置host,port
spring:
redis:
lettuce:
pool:
max-active: 1000
max-wait: -1
max-idle: 10
min-idle: 2
timeout: 2000
cluster:
nodes:
- 192.168.5.244:7000
配置CacheManager以及KeyGenerator
package com.rstim.user.cache.config;
...
@Configuration
@EnableCaching
@Slf4j
public class RedisCacheConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericFastJsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
/**
* redis缓存管理器
*/
@Bean
@Primary
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(this.cacheConfiguration(Duration.ofHours(6)))
.withInitialCacheConfigurations(this.cacheConfigurationMap())
.build();
return cacheManager;
}
/**
* redis缓存管理器配置列表;
* 可以根据业务需要配置不同的过期时间;
*/
private Map<String, RedisCacheConfiguration> cacheConfigurationMap() {
Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
configurationMap.put("m5", this.cacheConfiguration(Duration.ofMinutes(5)));
return configurationMap;
}
/**
* redis缓存管理器的默认配置;
* 使用fastJson序列化value,model不再需要实现Serializable接口;
*
* @param ttl 设置默认的过期时间,防止 redis 内存泄漏
*/
private RedisCacheConfiguration cacheConfiguration(Duration ttl) {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()))
.entryTtl(ttl);
return configuration;
}
/**
* 通用redis缓存key生成策略
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
for (Object obj : params) {
sb.append(CacheKeyUtil.getCacheKey(obj));
}
log.info("cacheKey={}", sb.toString());
return sb.toString();
}
};
}
}
自己写了一个工具类CacheKeyUtil,通过反射获取redis缓存key的后缀
主要用于解决更新缓存的场景时通常会传入pojo类,
而获取数据时通过传入id参数
package com.rstim.user.cache.utils;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
@Slf4j
public class CacheKeyUtil {
public static String getCacheKey(Object obj) {
if (obj == null) {
return "null";
}
Class clazz = obj.getClass();
if (clazz.equals(String.class) ||
clazz.equals(Integer.class) ||
clazz.equals(Long.class) ||
clazz.equals(Float.class) ||
clazz.equals(Double.class) ||
clazz.equals(Boolean.class) ||
clazz.equals(Character.class) ||
clazz.equals(Byte.class) ||
clazz.equals(Short.class)
) {
return obj.toString();
}
try {
Method method = clazz.getDeclaredMethod("cacheKey");
return (String) method.invoke(obj);
} catch (Exception e) {
log.warn("invoke cacheKey method fail, use default toString as cacheKey:", e);
return obj.toString();
}
}
}
使用时只需要在mysql表对应的java对象下实现一个如下方法:
public String cacheKey() {
return String.valueOf("这里根据业务添加redis缓存key的后缀,比如user的uuid");
}
更好的做法是定义一个CacheEntity接口:
package com.rstim.user.model.cache;
public interface CacheEntity {
/**
* 缓存的实体类实现本接口的cacheKey方法,可以指定缓存时 redis key的唯一后缀
*/
String cacheKey();
}
然后让需要进行缓存的java对象去实现CacheEntity接口
最后就可以通过 @Cacheable, @CachePut, @CacheEvit 实现redis缓存
package com.rstim.user.cache.service;
...
@Service
@CacheConfig(cacheNames = "userInfo")
public class UserInfoCacheService {
@Autowired
private UserInfoMapper userInfoMapper;
@CachePut
public UserInfo updateUserInfo(UserInfo userInfo) {
userInfoMapper.updateUserInfo(userInfo);
UserInfo updatedUser =userInfo;// userInfoMapper.selectById(userInfo.getUuid());
System.out.println("did not go cache");
return updatedUser;
}
@Cacheable
public UserInfo selectById(long uuid) {
UserInfo userInfo = new UserInfo(uuid);
System.out.println("did not go cache");
return userInfo;
}
@CacheEvict
public void deleteById(long uuid){
//delete from mysql;
}
}
小提示
- 只有被对象或者接口外部方法调用时,spring cache才会发生作用;
- 只有加在public方法上的注解,才会让 spring cache生效;
因为spring cache模式是使用java的动态代理来实现切面缓存,所以有上面两点限制,
如果想要在对象内部使spring cache生效,可以配置使用cglib来实现代理,具体
方法可以google.
网友评论