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

网友投稿 367 2023-01-15


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

导入redis的jar包

org.springframework.boot

spring-boot-starter-data-redis

2.0.4.RELEASE

编写自定义缓存注解

/**

* @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.utilWDeGUzswt.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 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 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 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() {

rWDeGUzswteturn 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 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);

}

}

总结

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:spring boot 开发soap webservice的实现代码
下一篇:Java实现获取指定个数的不同随机数
相关文章

 发表评论

暂时没有评论,来抢沙发吧~