通过Aop切面打印日志

前言:

        本次主要是提供了两种打印日志的方式,可供大家挑选

1.基于注解:

        优点:

                灵活

        缺点:

                工作量大,需要在每一个需要打印的地方加上注解,并且配置比较繁琐

        代码:

/**
 * 切点配置类
 */
@Slf4j
@Aspect
@Component
@EnableAspectJAutoProxy
public class AopConfig {
    /**
     * 方法用途(切入点表达式可以用&&,||,!来组合使用):
     *      execution: 匹配连接点:execution(* com.example.demo.*(..))--com.example.demo包下所有类的方法
     *      within: 某个类里面
     *      this: 指定AOP代理类的类型
     *      target:指定目标对象的类型
     *      args: 指定参数的类型
     *      bean:指定特定的bean名称,可以使用通配符(Spring自带的)
     *      @target: 带有指定注解的类型
     *      @args: 指定运行时传的参数带有指定的注解
     *      @within: 匹配使用指定注解的类
     *      @annotation:指定方法所应用的注解
     * <br/>
     * 操作步骤: TODO<br/>
     * ${tags}
     */
    @Pointcut("@annotation(com.deve.config.annotation.WinControllerPointCut)")
    public void winPointCut() {
    }


    /**
     * 前置通知
     * 方法用途:
     *      在winPointCut注解之前执行
     *      标识一个前置增强方法,相当于BeforeAdvice的功能.
     * <br/>
     * 操作步骤: TODO<br/>
     * ${tags}
     */
    @Async//异步注解
    @Before("winPointCut()")
    public void beforeCall(JoinPoint joinPoint) {
        log.info("日志记录开始-------------");
        //前置通知-业务,入参需要切点方法定义好
        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("before-接口路径:{}", request.getRequestURL().toString());
        log.info("before-请求方式:{}", request.getMethod());
        log.info("before-类方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("before-请求参数:" + Arrays.toString(joinPoint.getArgs()));

    }


    /**
     * 返回通知
     * 方法用途:
     *      在winPointCut注解之后执行
     *      final增强,不管是抛出异常或者正常退出都会执行。
     * @AfterReturning:  后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
     * @AfterThrowing:  异常抛出增强,相当于ThrowsAdvice.
     * <br/>
     * 操作步骤: TODO<br/>
     * ${tags}
     */
    @Async//异步注解
    @AfterReturning(pointcut = "winPointCut()", returning = "resp")
    public void returnCall(Object resp) {
        //后置通知-业务,入参需要切点方法定义好
        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("接口路径:{}", request.getRequestURL().toString());
        log.info("Result:{}", JSON.toJSONString(resp));
    }


    /**
     * 异常通知
     * @param jp
     * @param ex
     */
    @Async//异步注解
    @AfterThrowing(throwing = "ex", pointcut = "winPointCut()")
    public void throwsCall(JoinPoint jp,Exception ex){
        log.error("产生异常的方法:{}"+jp);
        log.error("异常种类:{}"+ex);
    }

    /**
     * 后置通知
     * @param jp
     */
    @Async//异步注解
    @After("winPointCut()")
    public void afterCall(JoinPoint jp){
        log.info("日志记录结束-------------");
    }

    /**
     * 环绕通知
     * 方法用途:
     *      @Around 环绕增强,相当于MethodInterceptor,对带@winPointCut注解的方法进行切面,并获取到注解的属性值
     *      ProceedingJoinPoint: 环绕通知
     * <br/>
     * 操作步骤: TODO<br/>
     * ${tags}
     */
    @Async  //异步注解
    //@Around("winPointCut() && @annotation(winControllerPointCut)")
    public Object aroundCall(ProceedingJoinPoint joinPoint, WinControllerPointCut winControllerPointCut) throws Throwable {
        Object obj = null;
        try {
            // winPointCut注解的属性值
            winControllerPointCut.remark();
            Object[] args = joinPoint.getArgs();
            String arg = JSON.toJSONString(args);
            log.info("请求参数:{}"+ arg);
            Signature signature = joinPoint.getSignature();
            // 方法package路径
            String methodUrl = signature.getDeclaringTypeName();
            // 方法名,不包含package路径
            String method = signature.getName();
            log.info("正在执行:{}" + method + "方法,路径:{}" + methodUrl);
            // obj是返回的结果,joinPoint.proceed用于启动目标方法执行,非常重要
            obj = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return obj;
    }
}






/**
 * 接口切点自定义注解,用于捕捉个别方法运行时详细情况
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface WinControllerPointCut {
    /**
     * 操作名称
     * @return
     */
    String remark() default "";

    /**
     * 操作类型
     * @return
     */
    String type() default "QUERY";
}

2.基于工具类

        优点:

                配置简单,操作方便

        缺点:

                会打印每一个方法,消耗比较大

        代码:

/**
 * 切点日志打印工具类
 * 打印所有请求的 url 、方法 、 参数
 */
@Aspect
@Component
@Slf4j
public class LogAspectUtils {
    /** 以 controller 包 的所有请求 为 切入点 */
    @Pointcut("execution(* com.deve.controller..*.*(..))")
    public void pointCat() {
    }

    /** 切点之前 */
    @Before("pointCat()")
    public void doBefore(JoinPoint joinPoint) {
        //获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        log.info("========================================== Start");
        log.info("请求地址             :{}", request.getRequestURL().toString());
        log.info("请求路径             :{}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        log.info("请求参数             :{}", JSON.toJSONString(joinPoint.getArgs()));
    }

    /**
     * 切点之后
     */
    @After("pointCat()")
    public void doAfter() {
        log.info("");
    }

    /**
     * 环绕
     */
    @Around("pointCat()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        log.info("开始时间              :{}", startTime);
        Object result = proceedingJoinPoint.proceed();
        log.info("返回参数              :{}", JSON.toJSONString(result).length()>=1000?"参数太大不打印了":JSON.toJSONString(result));
        long endTime = System.currentTimeMillis();
        log.info("结束时间              :{}", endTime);
        log.info("========================================== 执行耗时 :{} ms", endTime - startTime);
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/zjb1697922408/article/details/127885776