评论

收藏

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

编程语言 编程语言 发布于:2021-10-06 12:00 | 阅读数:387 | 评论:0

今天小编就为大家分享一篇关于SpringBoot AOP控制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);
  }
}
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对CodeAE代码之家的支持。如果你想了解更多相关内容请查看下面相关链接
原文链接:https://blog.csdn.net/qq_36476972/article/details/85710225

关注下面的标签,发现更多相似文章