定义注解
package com.ksyun.billing.rule.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SliceRuleCache {
public String cacheKey() default "";
public long expireTime() default 0L;
public String cachePreFix() default "slice";
}
解析注解
package com.ksyun.billing.rule.aspect
import com.alibaba.fastjson.JSON
import com.ksyun.billing.basic.execption.CommonException
import com.ksyun.billing.basic.execption.RuleBizException
import com.ksyun.billing.framework.exception.BizException
import com.ksyun.billing.rule.annotation.SliceRuleCache
import com.ksyun.billing.rule.constant.AlarmGroupNameEnum
import com.ksyun.billing.rule.service.InnerAlarmService
import com.ksyun.billing.rule.service.RedisHelper
import com.ksyun.ks3.utils.Jackson
import lombok.extern.slf4j.Slf4j
import org.apache.commons.lang3.StringUtils
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.Signature
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.annotation.Order
import org.springframework.stereotype.Component
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.List
import java.util.Optional
/**
* 切片缓存切面
*/
@Aspect
@Component
@Slf4j
public class SliceRuleCacheAspect {
@Autowired
private RedisHelper redisHelper
@Autowired
private InnerAlarmService innerAlarmService
@Pointcut("execution(public * com.ksyun.billing.rule.service.*.*(..))")
public void serviceAspectPointCut() {
}
@Pointcut("execution(public * com.ksyun.billing.rule.service.remote.*.*(..))")
public void remoteServiceAspectPointCut() {
}
@Pointcut("serviceAspectPointCut() || remoteServiceAspectPointCut()")
public void cacheAroundAspectPointCut() {
}
/**
* 需要在update操作前后分别获取更新前后的值
*
* @param
* @return
*/
@Around("cacheAroundAspectPointCut()")
public Object cacheAroundAspect(ProceedingJoinPoint joinPoint) throws Throwable {
Object proceedResult = null
//目标对象
Object targetClass = joinPoint.getTarget()
//切入点
Signature signature = joinPoint.getSignature()
MethodSignature methodSignature = (MethodSignature) signature
Object[] joinPointArgs = joinPoint.getArgs()
String signatureName = methodSignature.getName()
Class[] parameterTypes = methodSignature.getParameterTypes()
log.info("signatureName:{},parameterTypes:{}", signatureName, parameterTypes)
//目标方法
try {
Method targetMethod = targetClass.getClass().getMethod(signatureName, parameterTypes)
log.info("targetMethod:{}", targetMethod)
SliceRuleCache targetCacheAnnotation = targetMethod.getAnnotation(SliceRuleCache.class)
if (targetCacheAnnotation == null) {
proceedResult = joinPoint.proceed()
return proceedResult
}
long expireTime = targetCacheAnnotation.expireTime()
String cacheKey = getCacheKey(targetCacheAnnotation.cacheKey(), targetCacheAnnotation.cachePreFix(),
methodSignature,
joinPointArgs)
log.info("build cacheKey:{}", cacheKey)
String cacheResult = ""
try {
Optional<String> cacheOp = redisHelper.get(cacheKey)
if (cacheOp.isPresent()) {
cacheResult = cacheOp.get()
}
} catch (Exception ex) {
log.error("get cache from redis occur error,cacheKey:{}", cacheKey, ex)
innerAlarmService.innerAsyAlarmOnlyOnePiece(AlarmGroupNameEnum.INNER_EXCEPTION.getBizName(),
ex.getMessage())
}
if (StringUtils.isNotBlank(cacheResult)) {
//缓存存在
log.info("cache is exist,get result form cache,key:{}", cacheKey)
// 返回值数据类型是否为List
Class targetReturnClass = targetMethod.getReturnType()
if (methodSignature.getReturnType() == List.class) {
//为List则获取泛型的实际类型
if (targetMethod.getGenericReturnType() instanceof ParameterizedType) {
Type[] actualTypeArguments =
((ParameterizedType) targetMethod.getGenericReturnType()).getActualTypeArguments()
targetReturnClass = Class.forName(actualTypeArguments[0].getTypeName())
}
proceedResult = JSON.parseArray(cacheResult, targetReturnClass)
} else {//其他数据类型
proceedResult = JSON.parseObject(cacheResult, targetReturnClass)
}
} else {
//缓存不存在
proceedResult = joinPoint.proceed()
log.info("cache is not exist,get result form targetMethod:{}", targetMethod)
if (proceedResult != null) {
redisHelper.setex(cacheKey, Jackson.toJsonString(proceedResult),
Integer.valueOf(String.valueOf(expireTime)))
}
}
return proceedResult
} catch (Exception ex) {
log.error("cacheAroundAspect occur error", ex)
throw ex
}
}
/**
* cache key
*
* @param cacheKey
* @param methodSignature
* @param joinPointArgs
* @return
*/
private String getCacheKey(String cacheKey, String cachePreFix, MethodSignature methodSignature,
Object[] joinPointArgs) {
StringBuilder stringBuilder = new StringBuilder("")
//缓存前缀
if (StringUtils.isNotBlank(cachePreFix)) {
stringBuilder.append(cachePreFix).append("_")
}
//方法名
String methodSignatureName = methodSignature.getName()
stringBuilder.append(methodSignatureName)
//指定key
if (StringUtils.isNotBlank(cacheKey)) {
stringBuilder.append("_").append(cacheKey)
return stringBuilder.toString()
}
//方法参数当做缓存key
if (joinPointArgs != null && joinPointArgs.length > 0) {
for (Object obj : joinPointArgs) {
stringBuilder.append("_").append(obj)
}
}
return stringBuilder.toString()
}
}