Redis缓存注解
注解
@RedisCache 添加缓存
- 将注解添加到需要缓存的方法上,指定缓存的key
- 指定缓存保存的类
- 指定存活时间
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
String key() default "";
Class type();
long expireTime() default 3600L;
}
@RedisRelease 缓存释放
- 指定要释放的缓存的类
- 指定要释放哪个方法的缓存
- 是否清空redis中所有缓存
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisRelease {
Class[] type() default {};
String[] method() default {};
boolean releaseAll() default false;
}
添加了@RedisCache后执行方法后,会进入切面,判断是否命中缓存,如果命中缓存则返回缓存数据,没有命中,则会才回去查询数据库,再把数据缓存之后返回
添加了@RedisRelease执行方法后,会进入切面将缓存释放
切面类
@Aspect
@Component
@Slf4j
public class RedisCacheAspect {
@Autowired
private RedisTemplate redisTemplate;
private String prefix = "cache:thx";
@Around("@annotation(com.thx.redisaop.aop.RedisCache)")
public Object customerRedisCache(final ProceedingJoinPoint jp) throws Throwable {
Method method = getMethod(jp);
//获取方法上添加的注解
RedisCache redisCache = method.getAnnotation(RedisCache.class);
StringBuffer key = new StringBuffer();
// THX TODO 2023/11/9 15:28: 未来会解析参数并将参数拼到key中
//key默认为 prefix:缓存类的全类名:执行方法名:注解中指定的key值
key.append(prefix).append(":").append(redisCache.type().getName()).append(":").append(method.getName()).append(":").append(redisCache.key());
//获取注解中的要缓存的类
Class modelType = redisCache.type();
String value = (String) redisTemplate.opsForValue().get(key.toString());
Object resutl;
//判断redis中是否存缓存
if (value == null) {
log.info("未命中缓存,重新缓存");
//执行原方法获取数据
resutl = jp.proceed(jp.getArgs());
//将数据存入Redis作为缓存数据
String jsonString = JSON.toJSONString(resutl);
redisTemplate.opsForValue().set(key.toString(), jsonString,redisCache.expireTime(), TimeUnit.SECONDS);
} else {
//命中缓存
log.info("命中缓存,返回缓存数据");
//获取接口或方法的返回值类型
Class returnType = ((MethodSignature) jp.getSignature()).getReturnType();
resutl = deserialize(value, returnType, modelType);
return resutl;
}
return resutl;
}
@Around("@annotation(com.thx.redisaop.aop.RedisRelease)")
public Object customerRedisRelease(final ProceedingJoinPoint jp) throws Throwable {
Method method = getMethod(jp);
Class[] classes = method.getAnnotation(RedisRelease.class).type();
String[] methods = method.getAnnotation(RedisRelease.class).method();
//判断是否需要释放所有缓存
if (method.getAnnotation(RedisRelease.class).releaseAll()) {
Set keys = redisTemplate.keys(prefix + ":*");
if (CollectionUtils.isNotEmpty(keys)) {
redisTemplate.delete(keys);
}
} else if (classes.length > 0) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < classes.length; i++) {
Class classItem = classes[i];
String className = classItem.getName();
if (methods.length == 0) {
stringBuffer.setLength(0);
stringBuffer.append(prefix).append(":").append(className).append(":").append("*");
//获取模糊匹配的Key
Set keys = redisTemplate.keys(stringBuffer.toString());
if (CollectionUtils.isNotEmpty(keys)) {
redisTemplate.delete(keys);
}
log.info("删除指定类中所有方法的缓存:{}", stringBuffer.toString());
} else {
String classMethod = methods[i];
//如果指定了方法名则删除指定方法的缓存
if (StringUtils.isNotEmpty(classMethod)) {
List<String> methodNameList = Arrays.asList(classMethod.split(";"));
for (String methodName : methodNameList) {
stringBuffer.setLength(0);
stringBuffer.append(prefix).append(":").append(className).append(":").append(methodName).append(":").append("*");
Set keys = redisTemplate.keys(stringBuffer.toString());
if (CollectionUtils.isNotEmpty(keys)) {
redisTemplate.delete(keys);
}
log.info("删除指定类中指定方法的缓存:{}", stringBuffer.toString());
}
}
}
}
}
return jp.proceed(jp.getArgs());
}
/*
* 获取方法对象
* @author thx
* @date 2023/11/9
* @param jp
* @return Method
*/
public Method getMethod(ProceedingJoinPoint jp) {
Class[] types = ((MethodSignature) jp.getSignature()).getParameterTypes();
Method method = null;
try {
method = jp.getTarget().getClass().getMethod(jp.getSignature().getName(), types);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return method;
}
//通过获取的要缓存的类将数据进行反序列化
public Object deserialize(String jsonStr, Class clazz, Class modelType) {
//如果返回值是List对象
if (clazz.isAssignableFrom(List.class)) {
return JSON.parseArray(jsonStr, modelType);
}
return JSON.parseObject(jsonStr, Object.class, JSONReader.Feature.SupportAutoType);
}
}
使用示例
@RequestMapping("/redis")
@RestController
@Slf4j
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StudentService studentService;
@PostMapping("/add")
@RedisRelease(type = {Student.class}, method = {"test"} )
public void add(@RequestBody Student student){
studentService.save(student);
}
@GetMapping("/test")
@RedisCache(key = "stu",type = Student.class,expireTime = 180L)
public List<Student> test(){
return studentService.list();
}
}