软件编程
位置:首页>> 软件编程>> java编程>> SpringBoot AOP控制Redis自动缓存和更新的示例

SpringBoot AOP控制Redis自动缓存和更新的示例

作者:丶Melody  发布时间:2023-08-31 17:34:37 

标签:springboot,redis,缓存,更新

导入redis的jar包

<!-- redis -->
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
     <version>2.0.4.RELEASE</version>
   </dependency>

编写自定义缓存注解

/**
* @Description: redis缓存注解 编写在需要缓存的类上
**/
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
}

编写切面类

package com.ys.edu.aop;
import com.ys.edu.utils.ResultUtils;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import org.aspectj.lang.reflect.MethodSignature;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @ClassName RedisAOP
* @description: redis 切面缓存
**/
@Aspect
@Service
public class RedisAOP {
 private static final Logger logger = Logger.getLogger(RedisAOP.class);
 private static final Integer TIME_OUT = 30 ; //redis 存活时长 分钟
 @Resource
 private RedisTemplate redisTemplate;
 /**
  * @Title: queryCachePointcut
  * @Description: 定义切点为缓存注解
  * @return void
  **/
 @Pointcut("@within(com.ys.edu.annotation.RedisCache)")
 public void queryCachePointcut(){
 }
 @Around("queryCachePointcut()")
 public Object Interceptor(ProceedingJoinPoint joinPoint) throws Throwable{
   long beginTime = System.currentTimeMillis();
   MethodSignature signature = (MethodSignature) joinPoint.getSignature();
   //类路径名
   String classPathName = joinPoint.getTarget().getClass().getName();
   //类名
   String className = classPathName.substring(classPathName.lastIndexOf(".")+1,classPathName.length());
   //获取方法名
   String methodName = signature.getMethod().getName();
   String[] strings = signature.getParameterNames();
   String key = className+"_"+methodName+"_"+Arrays.toString(strings);
   if((methodName.indexOf("select") != -1 && methodName.substring(0,6).equalsIgnoreCase("select")) || (methodName.indexOf("query") != -1 && methodName.substring(0,5).equalsIgnoreCase("query")) || (methodName.indexOf("get") != -1 && methodName.substring(0,3).equalsIgnoreCase("get"))){
     Object data = getObject(beginTime,joinPoint,key);
     if(data != null){
       return ResultUtils.success(data);
     }
     return joinPoint.proceed();
   }else if((methodName.indexOf("add") != -1 && methodName.substring(0,3).equalsIgnoreCase("add")) || (methodName.indexOf("insert") != -1 && methodName.substring(0,6).equalsIgnoreCase("insert")) || (methodName.indexOf("update") != -1 && methodName.substring(0,6).equalsIgnoreCase("update"))){
     Set<String> keys = redisTemplate.keys(className+"*");
     redisTemplate.delete(keys);
     logger.warn("执行方法 : [ "+methodName+" ] : 清除 key 包含 [ "+className+" ] 的缓存数据");
     logger.warn("AOP 缓存切面处理 >>>> end 耗时:" + (System.currentTimeMillis() - beginTime));
   }
   // 调用原始方法
   return joinPoint.proceed();
 }
 /**
  * @Title: getObject
  * @Description: 使用key获取数据 不存在则查询添加
  * @param beginTime : 切面开始时间
  * @param joinPoint : 切面对象
  * @param key : 获取redis数据的key值
  * @return java.lang.Object
  **/
 private Object getObject(long beginTime,ProceedingJoinPoint joinPoint,String key) throws Throwable {
   ValueOperations<String, Object> operations = redisTemplate.opsForValue();
   boolean hasKey = redisTemplate.hasKey(key);
   Object object = null;
   if(hasKey){
     // 缓存中获取到数据,直接返回。
     object = operations.get(key);
     logger.warn("从缓存中获取到 key 为 ["+key+" ] : 的数据 >>>> " + object.toString());
     logger.warn("AOP 缓存切面处理 >>>> end 耗时:" + (System.currentTimeMillis() - beginTime));
     return object;
   }
   if(object == null) {
     // 缓存中没有数据,调用原始方法查询数据库
     object = joinPoint.proceed();
     operations.set(key, object, TIME_OUT, TimeUnit.MINUTES); // 设置超时时间30分钟
     logger.warn("向 Redis 添加 key 为 ["+key+" ] , 存活时长为 "+TIME_OUT+" min 的数据 >>>> " + object.toString());
     logger.warn("AOP 缓存切面处理 >>>> end 耗时:" + (System.currentTimeMillis() - beginTime));
   }
   return object;
 }
 @Autowired(required = false)
 public void setRedisTemplate(RedisTemplate redisTemplate) {
   RedisSerializer stringSerializer = new StringRedisSerializer();//序列化为String
   Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//序列化为Json
   redisTemplate.setKeySerializer(stringSerializer);
   redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
   redisTemplate.setHashKeySerializer(stringSerializer);
   redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
   this.redisTemplate = redisTemplate;
 }
}

在想要使用redis缓存的controller类上添加 @RedisCache 注解.

切面方法则会切以select/get/query 开头的查询方法,获取方法名和参数拼接为key,存到redis.

在执行add/insert/update 开头的方法时,则清空该类下的所有缓存.

方法返回值格式统一实体类:

package com.ys.edu.bean;
import java.io.Serializable;
/**
* @ClassName ResultBody
* @description: RestFul API 方法返回值格式统一实体类
**/
public class ResultBody<T> implements Serializable {
 private static final long serialVersionUID = 694858559908048578L;
 private Integer code;
 private String msg;
 private Integer count = 0;
 private T data;
 public ResultBody(){}
 public ResultBody(Integer code, String msg,Integer count,T data) {
   this.code = code;
   this.msg = msg;
   this.count = count;
   this.data = data;
 }
 public ResultBody(Integer code, String msg,T data) {
   this.code = code;
   this.msg = msg;
   this.data = data;
 }
 /**
  * @Title: success
  * @Description: 成功 (无参) 默认 code : " 0 " msg : "请求成功" , count : 0 , data: null
  * @date 2018/11/29 10:28
  **/
 public ResultBody success(){
   return success((T) null);
 }
 /**
  * @Title: success
  * @Description:  成功  默认 code : " 0 " msg : "请求成功"
  * @param count : 数据条数
  * @param data : 数据
  * @date 2018/11/29 11:46
  **/
 public ResultBody success(Integer count,T data){
   return new ResultBody(0,"请求成功!",count,data);
 }
 /**
  * @Title: success
  * @Description: 成功  默认 code : " 0 "
  * @param msg : 提示信息
  * @param count : 数据条数
  * @param data :  数据
  **/
 public ResultBody success(String msg,Integer count,T data){
   return new ResultBody(0,msg,count,data);
 }
 /**
  * @Title: success
  * @Description: 成功  默认 code : " 0 " , msg : "请求成功"
  * @param data : 数据
  **/
 public ResultBody success(T data){
   return new ResultBody(0,"请求成功!",data);
 }
 /**
  * @Title: success
  * @Description: 成功  默认 code : " 0 "
  * @param msg : 提示信息
  * @param data : 数据
  * @date 2018/11/29 11:47
  **/
 public ResultBody success(String msg,T data){
   return new ResultBody(0,msg,data);
 }
 /**
  * @Title: success
  * @Description: 成功  默认 code : " 0 "
  * @param code : 枚举类代码
  * @param data : 数据
  **/
 public ResultBody success(Code code,T data){
   return new ResultBody(code.getCode(),code.getMsg(),data);
 }
 /**
  * @Title: success
  * @Description: 成功  默认 code : " 0 "
  * @param code : 枚举类代码
  **/
 public ResultBody success(Code code){
   return new ResultBody(code.getCode(),code.getMsg(),null);
 }
 /**
  * @Title: error
  * @Description: 错误  默认 data : null
  * @param code : 错误代码
  * @param msg : 错误信息
  **/
 public ResultBody error(Integer code,String msg){
   return new ResultBody(code,msg,null);
 }
 /**
  * @Title: error
  * @Description: 错误  默认 data : null
  * @param code : 枚举类错误代码
  **/
 public ResultBody error(Code code){
   return new ResultBody(code.getCode(),code.getMsg(),null);
 }
 public Integer getCode() {
   return code;
 }
 public void setCode(Integer code) {
   this.code = code;
 }
 public String getMsg() {
   return msg;
 }
 public void setMsg(String msg) {
   this.msg = msg;
 }
 public Integer getCount() {
   return count;
 }
 public void setCount(Integer count) {
   this.count = count;
 }
 public T getData() {
   return data;
 }
 public void setData(T data) {
   this.data = data;
 }
}

自定义提示枚举类:

package com.ys.edu.bean;
/**
* @ClassName Code
* @description: 自定义提示枚举类
**/
public enum Code {
 /**
  * @Description: 请求状态码
  **/
 SUCCESS(0,"请求成功"),
 ERROR(-1,"请求错误");
 private Integer code;
 private String msg;
 public Integer getCode() {
   return code;
 }
 public void setCode(Integer code) {
   this.code = code;
 }
 public String getMsg() {
   return msg;
 }
 public void setMsg(String msg) {
   this.msg = msg;
 }
 Code(Integer code, String msg){
   this.code = code;
   this.msg = msg;
 }
}

返回结果工具类:

package com.ys.edu.utils;
import com.ys.edu.bean.Code;
import com.ys.edu.bean.ResultBody;
import com.ys.edu.entity.Page;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName ResultUtils
* @description: 返回结果工具类
**/
public class ResultUtils {
 /**
  * @Title: success
  * @Description: 无参成功返回  默认值 code : "0" , msg : "请求成功" , count : 0 , data : null
  **/
 public static ResultBody success(){
   return success((Object)null);
 }
 public static ResultBody success(Object object){
   return success(0,object);
 }
 /**
  * @Title: success
  * @Description: 有参成功返回  默认值 code : "0" , msg : "请求成功"
  * @param count : 数据条数
  * @param object : 数据
  **/
 public static ResultBody success(Integer count,Object object){
   return new ResultBody().success(count,object);
 }
 /**
  * @Title: success
  * @Description: 有参成功返回  默认值 code : "0"
  * @param msg : 提示信息
  * @param count : 数据条数
  * @param object : 数据
  **/
 public static ResultBody success(String msg,Integer count,Object object){
   return new ResultBody().success(msg,count,object);
 }
 /**
  * @Title: error
  * @Description: 有参成功返回   默认值 code : "0"
  * @param code :
  * @param object : 数据
  **/
 public static ResultBody success(Code code,Object object){
   return new ResultBody().success(code,object);
 }
 /**
  * @Title: error
  * @Description: 有参成功返回   默认值 code : "0" data : null
  * @param code : 枚举类代码
  **/
 public static ResultBody success(Code code){
   return new ResultBody().success(code);
 }
 /**
  * @Title: error
  * @Description: 错误返回格式   默认值 data : null
  * @param code : 错误代码
  **/
 public static ResultBody error(Integer code,String msg){
   return new ResultBody().error(code,msg);
 }
 /**
  * @Title: error
  * @Description: 错误返回格式   默认值 data : null
  * @param code : 枚举类错误代码
  **/
 public static ResultBody error(Code code){
   return new ResultBody().error(code);
 }
 /**
  * @Title: successByLimit
  * @Description: 分页返回数据格式
  * @param page : 查询的页数
  * @param limit : 查询的条数
  * @param totalNum : 数据总条数
  * @param curCount : 当前页条数
  * @param object : 查询结果数据
  **/
 public static ResultBody successByLimit(Integer page,Integer limit,Integer totalNum,Integer curCount,Object object){
   Map<String,Object> map = new HashMap<>();
   Page pageInfo = new Page();
   pageInfo.setPage(page);
   pageInfo.setLimit(limit);
   pageInfo.setTotalNum(totalNum);
   pageInfo.setTotalPages((totalNum + limit - 1)/limit);
   map.put("page",pageInfo);
   map.put("data",object);
   return success(curCount,map);
 }
}

来源:https://blog.csdn.net/qq_36476972/article/details/85710225

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com