9 changed files with 215 additions and 4 deletions
@ -0,0 +1,35 @@ |
|||
package com.qs.serve.common.framework.annotations; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
/** |
|||
* 解决原有@CacheAble不支持独立失效策略场景 |
|||
* @author YenHex |
|||
* @since 2024/10/17 |
|||
*/ |
|||
@Target({ElementType.METHOD}) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
public @interface RedisCacheable { |
|||
|
|||
/** |
|||
* redis缓存前缀,默认类与方法名 |
|||
* @return |
|||
*/ |
|||
String prefix() default ""; |
|||
|
|||
/** |
|||
* 过期时间 |
|||
* @return |
|||
*/ |
|||
int expire() default 350; |
|||
|
|||
/** |
|||
* 缓存读取主键表达式 |
|||
* @return |
|||
*/ |
|||
String expression() default ""; |
|||
|
|||
String SIMPLE_KEY = "#key"; |
|||
|
|||
} |
@ -0,0 +1,135 @@ |
|||
package com.qs.serve.common.framework.aop; |
|||
|
|||
import com.baomidou.mybatisplus.core.toolkit.StringPool; |
|||
import com.qs.serve.common.framework.annotations.RedisCacheable; |
|||
import com.qs.serve.common.framework.redis.RedisService; |
|||
import com.qs.serve.common.util.JsonUtil; |
|||
import com.qs.serve.common.util.StringUtils; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.aspectj.lang.ProceedingJoinPoint; |
|||
import org.aspectj.lang.Signature; |
|||
import org.aspectj.lang.annotation.Around; |
|||
import org.aspectj.lang.annotation.Aspect; |
|||
import org.aspectj.lang.annotation.Pointcut; |
|||
import org.aspectj.lang.reflect.MethodSignature; |
|||
import org.springframework.core.annotation.AnnotatedElementUtils; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.lang.reflect.Method; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* @author YenHex |
|||
* @since 2024/10/18 |
|||
*/ |
|||
@Slf4j |
|||
@Aspect |
|||
@Component |
|||
@AllArgsConstructor |
|||
public class RedisCacheAspect { |
|||
|
|||
private final RedisService redisService; |
|||
|
|||
@Pointcut("@annotation(com.qs.serve.common.framework.annotations.RedisCacheable)") |
|||
public void PointCut() {} |
|||
|
|||
@Around("PointCut()") |
|||
public Object redisCacheAdvice(ProceedingJoinPoint joinPoint) throws Throwable { |
|||
Object[] args = joinPoint.getArgs(); |
|||
Signature signature = joinPoint.getSignature(); |
|||
MethodSignature methodSignature = ((MethodSignature) signature); |
|||
Method method = methodSignature.getMethod(); |
|||
RedisCacheable redisCacheable = AnnotatedElementUtils.findMergedAnnotation(method, RedisCacheable.class); |
|||
if(redisCacheable!=null){ |
|||
String prefix = StringUtils.hasText(redisCacheable.prefix()) ? redisCacheable.prefix() |
|||
: methodSignature.getDeclaringType().getName() +"."+ methodSignature.getMethod().getName()+"()"; |
|||
//构建表达式key
|
|||
String pk = this.getPrimaryKey(methodSignature,redisCacheable,args); |
|||
String redisCacheKey = "RCache:" + prefix + (pk==null?"":pk); |
|||
Object result = redisService.get(redisCacheKey); |
|||
if(result!=null){ |
|||
return JsonUtil.jsonToMap(result.toString()); |
|||
} |
|||
result = joinPoint.proceed(args); |
|||
if(result!=null){ |
|||
redisService.set(redisCacheKey,JsonUtil.objectToJson(result),redisCacheable.expire(), TimeUnit.MILLISECONDS); |
|||
} |
|||
return result; |
|||
} |
|||
// 返回默认对象
|
|||
return joinPoint.proceed(args); |
|||
} |
|||
|
|||
public String getPrimaryKey(MethodSignature methodSignature,RedisCacheable annotation,Object[] args){ |
|||
String method = methodSignature.getDeclaringType().getName() |
|||
+"."+ methodSignature.getMethod().getName()+"()"; |
|||
final String expression = annotation.expression(); |
|||
//适配表达式读取key,key读取不到log.error,放行请求
|
|||
String primaryKey = null; |
|||
if(StringUtils.isNotEmpty(expression)){ |
|||
//
|
|||
if(expression.equals(RedisCacheable.SIMPLE_KEY)&&args.length==1){ |
|||
return args[0].toString(); |
|||
} |
|||
List<String> keys = new ArrayList<>(); |
|||
// 指定表名
|
|||
String tableName = null; |
|||
if(expression.contains(StringPool.DOT)){ |
|||
String[] keyArr = expression.split(StringPool.BACK_SLASH + StringPool.DOT); |
|||
for (String key : keyArr) { |
|||
if(key.contains(StringPool.DOLLAR)){ |
|||
tableName = key.replace(StringPool.DOLLAR,""); |
|||
continue; |
|||
} |
|||
keys.add(key); |
|||
} |
|||
}else { |
|||
keys.add(expression); |
|||
} |
|||
for (Object arg : args) { |
|||
// 跳过非指定的表名
|
|||
if(tableName!=null){ |
|||
String clazzName = arg.getClass().getSimpleName(); |
|||
if(!clazzName.equals(tableName)){ |
|||
continue; |
|||
} |
|||
} |
|||
// 读取key
|
|||
primaryKey = getPrimaryKeyRecursion(keys, arg, 0); |
|||
} |
|||
if(primaryKey==null){ |
|||
log.error("LockSubmitAspect失效,方法:{} 无法读取主键:{}",method,expression); |
|||
} |
|||
} |
|||
return primaryKey; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 递归读取主键 |
|||
* @param keys |
|||
* @param arg |
|||
* @param startIndex |
|||
* @return |
|||
*/ |
|||
private String getPrimaryKeyRecursion(List<String> keys, Object arg, int startIndex) { |
|||
String key = keys.get(startIndex); |
|||
Map<String,Object> param = JsonUtil.jsonToMap(JsonUtil.objectToJson(arg)); |
|||
Object val = param.get(key); |
|||
if(val!=null){ |
|||
boolean isLast = startIndex + 1== keys.size(); |
|||
if(isLast){ |
|||
return val.toString(); |
|||
}else { |
|||
// 自调支持无限层级
|
|||
return getPrimaryKeyRecursion(keys, val, startIndex + 1 ); |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
} |
Loading…
Reference in new issue