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

时间:2022-10-11 15:05:22

导入redis的jar包

?
1
2
3
4
5
6
<!-- redis -->
    <dependency>
      <groupid>org.springframework.boot</groupid>
      <artifactid>spring-boot-starter-data-redis</artifactid>
      <version>2.0.4.release</version>
    </dependency>

编写自定义缓存注解

?
1
2
3
4
5
6
7
8
/**
 * @description: redis缓存注解 编写在需要缓存的类上
 **/
@documented
@target(elementtype.type)
@retention(retentionpolicy.runtime)
public @interface rediscache {
}

编写切面类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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 开头的方法时,则清空该类下的所有缓存.

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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;
  }
}

自定义提示枚举类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;
  }
}

返回结果工具类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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