一、引入相关依赖
<!--springData操作redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、配置redis
spring:
redis:
host: 123.456.789.123 #ip地址
port: 8888 #端口号
database: 8 #操作的库
password: 123456
三、创建一个切面类
package com.zsq.cache;
import com.alibaba.fastjson.JSON;
import com.micro.product.annotation.AddCache;
import com.micro.product.annotation.DelCache;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration //声明这个类是配置类
@Aspect //定义这是切面类
public class RedisCache {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 添加缓存方法
* @Around注解是: 定义是环绕方法
* @annotation(com.zsq.annotcation.AddCache)
* @AddCache是自定义注解,把注解放在要添加缓存的方法上
*/
@Around("@annotation(com.zsq.annotcation.AddCache)")
public Object around(ProceedingJoinPoint proceedingJoinPoint){
//获取方法签名
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
//获取被拦截的方法
Method method = signature.getMethod();
//获取方法上的注解信息
AddCache addCache = method.getAnnotation(AddCache.class);
//校验是否配置缓存key
String key = addCache.key();
if (StringUtils.isEmpty(key)) {
//获取类的全路径名称
key = proceedingJoinPoint.getTarget().getClass().getName();
}
//判断key前缀是否存在
if (!StringUtils.isEmpty(addCache.keyPrefix())) {
key = addCache.keyPrefix() + ":" + key;
}
//获取所有hashKey
String hashKey = addCache.hashKey();
if (StringUtils.isEmpty(hashKey)) {
//获取类的全路径名称
hashKey = proceedingJoinPoint.getSignature().getName();
}
//判断hashKey前缀是否存在
if (!StringUtils.isEmpty(addCache.keyHashPrefix())) {
hashKey = addCache.keyHashPrefix() + ":" + hashKey;
}
//创建存储方法中参数的数组
Object[] args = null;
//校验是否要携带参数信息
if (addCache.carryArgs()) {
//获取所有参数
args = proceedingJoinPoint.getArgs();
//判断是否有移除的参数
int[] removeArgsIndex = addCache.removeArgsIndex();
//判断方法参数不为空,并且需要移除无用参数
if (ArrayUtils.isNotEmpty(args) && ArrayUtils.isNotEmpty(removeArgsIndex)) {
//创建存储
ArrayList<Object> argList = new ArrayList<>();
//将数组转集合
List<Integer> removeArgsIndexList = Arrays.asList(ArrayUtils.toObject(removeArgsIndex));
for (int i = 0; i < args.length; i++) {
//存储不移除的参数信息
if (!removeArgsIndexList.contains(i)) {
argList.add(args[i]);
}
}
args = argList.toArray();
}
}
//判断参数信息是否为空,不为空则拼接到hashKey中
if (ArrayUtils.isNotEmpty(args)) {
hashKey = hashKey + ":" + JSON.toJSONString(args);
}
HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();
//判断缓存中是否有数据
Boolean hasKey = opsForHash.hasKey(key, hashKey);
Object result = null;
if (hasKey) {
//如果有返回数据
result = opsForHash.get(key, hashKey);
} else {
//把数据存到redis中
try {
//获取切入方法的返回值
result = proceedingJoinPoint.proceed();
//存储到redis中
opsForHash.put(key, hashKey, result);
//获取是否设置超时时间
long timeout = addCache.timeout();
if (timeout != -1) {
//设置可以超时时间
redisTemplate.expire(key, timeout, addCache.unit());
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
return result;
}
/**
* 清空缓存
* @After:后置通知
* @annotation(com.zsq.annotcation.DelCache)
* @DelCache是自定义注解,把注解放在要清空缓存的方法上
*/
@After("@annotation(com.zsq.annotcation.DelCache)")
public void after(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取被拦截的方法
Method method = signature.getMethod();
DelCache delCache = method.getAnnotation(DelCache.class);
//获取要清除的key
String[] keys = delCache.key();
//判断清除key是否为空,如果为空默认为方法名
if (ArrayUtils.isEmpty(keys)) {
keys = new String[]{joinPoint.getTarget().getClass().getName()};
}
//获取所有的hashKey
String[] hashKeys = delCache.hashKey();
try {
//校验hashKey是否为空,如果不为为空则直接删除key
if (ArrayUtils.isEmpty(hashKeys)) {
//校验hashKey是否配置前缀
String keyPrefix = delCache.keyPrefix();
//删除hashKey
for (String key : keys) {
redisTemplate.delete(StringUtils.isEmpty(keyPrefix) ? key : keyPrefix + ":" + key);
}
} else {
HashOperations<String, String, Object> operations = redisTemplate.opsForHash();
String keyHashPrefix = delCache.keyHashPrefix();
//删除每个key的hashKey
for (String key : keys) {
for (String hashKey : hashKeys) {
operations.delete(key, StringUtils.isEmpty(keyHashPrefix) ? hashKey : keyHashPrefix + ":" + hashKey);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、创建自定义注解
放在你要切的方法上
package com.zsq.annotcation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 添加缓存注解
*/
@Target(ElementType.METHOD)//只能在方法上生命声明
@Retention(RetentionPolicy.RUNTIME)//运行时生效
public @interface AddCache {
/**
* key前缀
*
* @return
*/
String keyPrefix() default "";
/**
* redis存储key
* 默认是当前使用注解方法的全路径类名
*
* @return
*/
String key() default "";
/**
* hashKey前缀
*
* @return
*/
String keyHashPrefix() default "";
/**
* redis存储hashKey
* 默认是当前使用注解方法的 方法名:参数
*
* @return
*/
String hashKey() default "";
/**
* hashKey是否携带参数
*
* @return
*/
boolean carryArgs() default true;
/**
* 要移除携带参数的下标,从0开始
*
* @return
*/
int[] removeArgsIndex() default {};
/**
* 设置key超时时间
* @return
*/
long timeout() default -1;
/**
* 设置超时时间单位,默认为秒
* @return
*/
TimeUnit unit() default TimeUnit.SECONDS;
}
package com.zsq.annotcation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 清空缓存注解
*/
@Target(ElementType.METHOD)//只能在方法上使用
@Retention(RetentionPolicy.RUNTIME)//运行时生效
public @interface DelCache {
/**
* key前缀
*
* @return
*/
String keyPrefix() default "";
/**
* redis存储key
* 默认是当前使用注解方法的全路径类名
*
* @return
*/
String[] key() default {};
/**
* hashKey前缀
*
* @return
*/
String keyHashPrefix() default "";
/**
* redis存储hashKey
* 默认删除当前key下的所有hash信息
*
* @return
*/
String[] hashKey() default {};
}