springAOP+redis实现缓存
思路
环境准备
maven依赖
<!--springData操作redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--springboot实现切面编程-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
把redis搭建好后,使用springboot配置连接redis参数
spring:
redis:
host: 192.168.17.149 #ip地址
port: 6379 #端口号
database: 2 #操作的库
准备自定义注解
将需要添加缓存的方法上加入注解@AddCache
将需要删除缓存的方法上加入注解@DelCache
@Target(ElementType.METHOD)//使用在方法上
@Retention(RetentionPolicy.RUNTIME)//运行时生效
public @interface AddCache {
}
@Target(ElementType.METHOD)//使用在方法上
@Retention(RetentionPolicy.RUNTIME)//运行时生效
public @interface DelCache {
}
实现添加缓存、删除缓存
String类型
Key=(包名+类名+方法名+实参)String,Value=(数据)String
@Aspect
@Configuration
public class CacheAspect {
//注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//添加缓存
@Around("@annotation(com.baizhi.annotation.AddCache)")//环绕通知+切注解
public Object addRedisCache(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("==环绕通知 加入缓存==");
//解决乱码问题
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//用于拼接(包名+类名+方法名+实参)
StringBuilder sb = new StringBuilder();//可变长字符串
//获取类的全限定名
String className = proceedingJoinPoint.getTarget().getClass().getName();
sb.append(className);
//获取方法名
String methodName = proceedingJoinPoint.getSignature().getName();
sb.append(methodName);
//获取参数(实参)
Object[] args = proceedingJoinPoint.getArgs();
for (Object arg: args){
sb.append("."+arg);
}
//获取key(包名+类名+方法名+实参)
String key = sb.toString();
ValueOperations string = redisTemplate.opsForValue();
//☆根据key去redis中判断有无数据,有:true 无:false
Boolean aBoolean = redisTemplate.hasKey(key);
Object result=null;
if (aBoolean){
//1、有数据 取出数据,返回结果
result = string.get(key);
}else {
//2、没有数据 查询数据库获取结果,加入缓存,返回结果
//①放行方法 查询数据库取出结果
try {
result = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//②获取的返回结果加入缓存
string.set(key,result);
}
return result;
}
//清除缓存
@After("@annotation(com.baizhi.annotation.DelCache)")//后置通知+切注解
public void delCache(JoinPoint joinPoint){
System.out.println("==后置通知 清除缓存==");
//获取类的全限定名(包名+类名)
String className = joinPoint.getTarget().getClass().getName();
//获取所有的key
Set<String> keys = stringRedisTemplate.keys("*");
for (String key : keys) {
//判断当前key是否是以className开头的
if (key.startsWith(className)){
//有:删除key
stringRedisTemplate.delete(key);
}
}
}
}
优化添加缓存、删除缓存
Hash类型
Key=(类的全限定名)String,Value=( key=(方法名+实参)String,value=(数据)String )
@Aspect
@Configuration
public class CacheAspectHash {
//注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
@Autowired
StringRedisTemplate stringRedisTemplate;
//添加缓存
@Around("@annotation(com.baizhi.annotation.AddCache)")//环绕通知+切注解
public Object addRedisCache(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("==环绕通知 加入缓存==");
/*
* 解决序列化乱码
* */
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//Key=类的全限定名,Value=( key=方法名+实参,value=数据 )
//获取类的全向定名 com/baizhi/impl/feedbackServiceImpl
String className = proceedingJoinPoint.getTarget().getClass().getName();
StringBuilder sb = new StringBuilder();
//获取方法名
String methodName = proceedingJoinPoint.getSignature().getName();
sb.append(methodName);
//获取参数
Object[] args = proceedingJoinPoint.getArgs();
for (Object arg: args){
sb.append("."+arg);
}
//获取小key
String key = sb.toString();
HashOperations hash = redisTemplate.opsForHash();
//☆判断大key中有没有小key,有:true 无:false
Boolean aBoolean = hash.hasKey(className, key);
Object result=null;
if (aBoolean){
//1、有数据 取出数据,返回结果
result = hash.get(className,key);
}else {
//2、没有数据 查询数据库获取结果,加入缓存,返回结果
//①放行方法 查询数据库取出结果
try {
result = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//②获取的返回结果加入缓存
hash.put(className,key,result);
}
return result;
}
//清除缓存
@After("@annotation(com.baizhi.annotation.DelCache)")//后置通知+切注解
public void delXCache(JoinPoint joinPoint){
System.out.println("==后置通知 清除缓存==");
//Key=类的全限定名,Value=( key=方法名+实参,value=数据 )
//获取类的全限定名
String className = joinPoint.getTarget().getClass().getName();
Boolean bBoolean = stringRedisTemplate.delete(className);
System.out.println("删除缓存"+bBoolean);
}
}