导入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

SpringBoot AOP控制Redis自动缓存和更新的更多相关文章

  1. 基于aop的redis自动缓存实现

    目的: 对于查询接口所得到的数据,只需要配置注解,就自动存入redis!此后一定时间内,都从redis中获取数据,从而减轻数据库压力. 示例: package com.itliucheng.biz; ...

  2. (十五)SpringBoot之使用Redis做缓存数据

    一.添加Redis依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=" ...

  3. java基于注解的redis自动缓存实现

    目的: 对于查询接口所得到的数据,只需要配置注解,就自动存入redis!此后一定时间内,都从redis中获取数据,从而减轻数据库压力. 示例: package com.itliucheng.biz; ...

  4. 注解+AOP实现redis遍历缓存

    1.注解 package com.yun.smart.annotation; import java.lang.annotation.ElementType; import java.lang.ann ...

  5. SpringBoot集成Redis实现缓存处理(Spring AOP实现)

    第一章 需求分析 计划在Team的开源项目里加入Redis实现缓存处理,因为业务功能已经实现了一部分,通过写Redis工具类,然后引用,改动量较大,而且不可以实现解耦合,所以想到了Spring框架的A ...

  6. 深入理解Spring Redis的使用 (八)、Spring Redis实现 注解 自动缓存

    项目中有些业务方法希望在有缓存的时候直接从缓存获取,不再执行方法,来提高吞吐率.而且这种情况有很多.如果为每一个方法都写一段if else的代码,导致耦合非常大,不方便后期的修改. 思来想去,决定使用 ...

  7. spring-boot集成mybatis,用redis做缓存

    网上有很多例子了,执行源码起码有3个,都是各种各样的小问题. 现在做了个小demo,实现spring-boot 用redis做缓存的实例,简单记录下思路,分享下源码. 缓存的实现,分担了数据库的压力, ...

  8. Springboot使用Shiro-整合Redis作为缓存 解决定时刷新问题

    说在前面 (原文链接: https://blog.csdn.net/qq_34021712/article/details/80774649)本来的整合过程是顺着博客的顺序来的,越往下,集成的越多,由 ...

  9. SpringBoot学习笔记(10)-----SpringBoot中使用Redis/Mongodb和缓存Ehcache缓存和redis缓存

    1. 使用Redis 在使用redis之前,首先要保证安装或有redis的服务器,接下就是引入redis依赖. pom.xml文件如下 <dependency> <groupId&g ...

随机推荐

  1. 巨蟒python全栈开发flask2

    内容回顾: 上节回顾: Flask .response 三剑客: render_template 模板 redirect 重定向 - URL地址 "" 字符串 HTTPRespon ...

  2. Oracle数据库的归档模式(archivelog mode)

    Oracle数据库可以运行在2种模式下: 归档模式(archivelog) 归档模式可以提高Oracle数据库的可恢复性,生产数据库都应该运行在此模式下,归档模式应该和相应的备份策略相结合,只有归档模 ...

  3. PHP中Trait详解及其应用

    w PHP中Trait详解及其应用 - 开发者日常 - SegmentFaulthttps://segmentfault.com/a/1190000008009455

  4. 学习js的正确姿势

    轻松入门: http://dwz.cn/6yYLoo 全面理解: http://www.shouce.ren/api/view/a/1116 大师进阶: http://es6.ruanyifeng.c ...

  5. unix_timestamp 和 from_unixtime 时间戳函数 区别

    1.unix_timestamp 将时间转化为时间戳.(date 类型数据转换成 timestamp 形式整数) 没传时间参数则取当前时间的时间戳 mysql> select unix_time ...

  6. Web 编程中路径问题

    web.xml 中 <url-pattern> 路径(即 Servlet 路径) 要么以 "*" 开头, 要么以 "/" 开头. 转发和包含路径(服 ...

  7. 转!!CSRF攻击与防御(写得非常好)

    CSRF概念:CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:       攻击者盗用了你的身份,以你的名义发送恶 ...

  8. django博客项目1.环境搭建

    安装 Python Windows 下安装 Python 非常简单,去 Python 官方网站找到 Python 3 的下载地址,根据你的系统选择 32 位或者 64 位的安装包,下载好后双击安装即可 ...

  9. 我的Android进阶之旅------>关于使用Android Studio替换App的launcher图标之后仍然显示默认的ic_launcher图标的解决方法

    前言 最近做了一个App,之前开发该App的时候一直以来都是默认的launcher图标启动的, 今天美工换了一个App的launcher 图标,因此在Android Studio中将默认的lanche ...

  10. Flask(1)- 主流web框架、初识flask

    一.Python 现阶段三大主流Web框架 Django.Tornado.Flask 对比 Django 主要特点是大而全,集成了很多组件(例如Models.Admin.Form等等), 不管你用得到 ...