java-切面编程-自定义注解

152 阅读1分钟

定义注解

package com.ksyun.billing.rule.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SliceRuleCache {


    /**
     * 缓存key
     * @return
     */
    public String cacheKey() default "";

    /**
     * 过期时间
     * 单位秒
     * @return
     */
    public long expireTime() default 0L;


    /**
     * 缓存前缀
     * @return
     */
    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();

    }


}