0
点赞
收藏
分享

微信扫一扫

Aspect 执行


import com.google.common.collect.Maps;
import com.lvym.support.annotation.LvymCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

/**
 * @desc
 * @since 2024/9/29
 * <p>
 * 版本不一样  执行顺序不同
 * <p>
 * 5.1.5
 * : 环绕通知前置拼接缓存key: user:1
 * : 前置通知参数 1
 * : 环绕通知后置返回查询DB返回
 * : 后置通知>>>
 * : 返回结果通知查询DB返回
 * <p>
 * <p>
 * 环绕通知没有捕获异常:
 * 环绕通知前置拼接缓存key: user:2
 * : 前置通知参数 2
 * : 后置通知>>>
 * : 异常通知方法
 * <p>
 * <p>
 * 6.0.4
 * <p>
 * 环绕通知前置拼接缓存key: user:1
 * : 前置通知参数 1
 * : 返回结果通知查询DB返回
 * : 后置通知>>>
 * : 环绕通知后置返回查询DB返回
 * <p>
 * <p>
 * 环绕通知前置拼接缓存key: user:2
 * : 前置通知参数 2
 * : 异常通知方法
 * : 后置通知>>>
 */
@Component
@Aspect
@Slf4j
public class UserAspect {

    private final Map<String, Object> tempCache = Maps.newConcurrentMap();

    @Pointcut("@annotation(com.lvym.support.annotation.LvymCache)")
    public void pointCut() {
    }


    /***
     * 前置通知
     */
    @Before("pointCut()")
    public void deBefore(JoinPoint joinPoint) {
        log.info("前置通知参数 {}", joinPoint.getArgs());
        final Signature signature = joinPoint.getSignature();
        //log.info("接口名称 name {}", signature.getName());
        //log.info("类名 declaringTypeName {}", signature.getDeclaringTypeName());

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;  //只做显示,没有实际作用
        HttpServletRequest request = attributes.getRequest();
        //log.info("接口地址 {}", request.getRequestURL().toString());
        //log.info("接口请求方式 {}", request.getMethod());

    }

    /***
     * 后置通知
     */
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        log.info("后置通知>>>");
    }

    /***
     * 返回结果通知
     */
    @AfterReturning(returning = "o", pointcut = "pointCut()")
    public void afterReturning(Object o) {
        log.info("返回结果通知{}", o);
    }

    /***
     * 异常通知
     */
    @AfterThrowing(throwing = "e", pointcut = "pointCut()")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        log.info("异常通知方法 {},异常{}", joinPoint, e.getMessage());
    }


    //@Around("execution(* com.lvym.support.service.impl.UserServiceImpl.*())")
    @Around("pointCut()")
    public Object methodExporter(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        LvymCache lvymCacheAnnotation = method.getAnnotation(LvymCache.class);
        String cacheType = lvymCacheAnnotation.cacheType();
        String matchValue = lvymCacheAnnotation.matchValue();
        String keyPrefix = lvymCacheAnnotation.keyPrefix();
        //SpringEL 解析器
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(matchValue);
        EvaluationContext context = new StandardEvaluationContext();

        //获得方法里面的形参个数
        Object[] args = proceedingJoinPoint.getArgs();
        //以第一参数为准
        if (isPrimitive(args[0])) {
            //非对象
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discoverer.getParameterNames(method);
            for (int i = 0; i < Objects.requireNonNull(parameterNames).length; i++) {
                context.setVariable(parameterNames[i], args[i].toString());
            }
        } else {
            for (Object arg : args) {
                //获取对象的Class对象
                Class<?> aClass = arg.getClass();
                //获取Class对象中的所有字段
                Field[] declaredFields = aClass.getDeclaredFields();
                //遍历字段
                for (Field field : declaredFields) {
                    //参数名
                    String name = field.getName();
                    //设置字段的可访问性
                    field.setAccessible(true);
                    //参数值
                    Object obj = field.get(arg);
                    context.setVariable(name, obj);
                }
            }
        }
        //拼接redis的最终key形式
        String key = keyPrefix + ":" + expression.getValue(context);
        log.info("环绕通知前置拼接缓存key: {}", key);
        Object object = tempCache.get(key);
        if (Objects.nonNull(object)) {
            return object;
        } else {
            Object proceed = proceedingJoinPoint.proceed();
            if (Objects.nonNull(proceed)) {
                tempCache.put(key, proceed);
            }
            log.info("环绕通知后置返回{}", proceed);
            return proceed;
        }
    }

    public static boolean isPrimitive(Object param) {
        return param instanceof Integer ||
                param instanceof Float ||
                param instanceof Double ||
                param instanceof Long ||
                param instanceof Boolean ||
                param instanceof Character ||
                param instanceof Byte ||
                param instanceof Short;
    }

}

@SpringBootApplication
//@EnableAspectJAutoProxy   spring-boot-starter-web--->spring-boot-autoconfigure  会自动装配
public class LvymSupportApplication {

    public static void main(String[] args) {
        SpringApplication.run(LvymSupportApplication.class, args);
    }

}

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>



举报

相关推荐

0 条评论