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

 更新时间:2019年01月05日 08:58:01   作者:丶Melody  
今天小编就为大家分享一篇关于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);
  }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

相关文章

  • Spring定时任务@scheduled多线程使用@Async注解示例

    Spring定时任务@scheduled多线程使用@Async注解示例

    这篇文章主要为大家介绍了Spring定时任务@scheduled多线程使用@Async注解示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Mybatis模糊查询和动态sql语句的用法

    Mybatis模糊查询和动态sql语句的用法

    今天小编就为大家分享一篇关于Mybatis模糊查询和动态sql语句的用法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • SpringBoot读取配置文件常用方法解析

    SpringBoot读取配置文件常用方法解析

    这篇文章主要介绍了SpringBoot读取配置文件常用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Java实现添加条码或二维码到Word文档

    Java实现添加条码或二维码到Word文档

    这篇文章主要介绍了如何在Word文档中添加条码、二维码。可在文档正文段落中添加,也可在页眉页脚中添加,感兴趣的小伙伴快跟随小编一起学习一下吧
    2022-05-05
  • Mybatis常用注解中的SQL注入实例详解

    Mybatis常用注解中的SQL注入实例详解

    MyBatis是一款优秀的持久层框架,它支持定制化 SQL(灵活)、存储过程(PLSQL模块化的组件,数据库的一部分)以及高级映射(表映射为Bean也可以将Bean映射为表),下面这篇文章主要给大家介绍了关于Mybatis常用注解中的SQL注入的相关资料,需要的朋友可以参考下
    2022-02-02
  • Java正确实现一个单例设计模式的示例

    Java正确实现一个单例设计模式的示例

    今天小编就为大家分享一篇关于Java正确实现一个单例设计模式的示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • SpringBoot实现线程池

    SpringBoot实现线程池

    现在由于系统越来越复杂,导致很多接口速度变慢,这时候就会想到可以利用线程池来处理一些耗时并不影响系统的操作。本文就介绍了SpringBoot线程池的使用,感兴趣的可以了解一下
    2021-06-06
  • 教你Spring如何使用三级缓存解决循环依赖

    教你Spring如何使用三级缓存解决循环依赖

    这篇文章主要介绍了Spring使用三级缓存解决循环依赖的过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • 简单了解Spring Bean常用注解的装配

    简单了解Spring Bean常用注解的装配

    这篇文章主要介绍了简单了解Spring Bean常用注解的装配,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • hibernate批量操作实例详解

    hibernate批量操作实例详解

    这篇文章主要介绍了hibernate批量操作,结合实例形式分析了Hibernate实现批量插入,更新及删除等操作的具体实现技巧,需要的朋友可以参考下
    2016-03-03

最新评论