欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot使用AOP做日志管理

程序员文章站 2022-04-25 19:37:47
...
package com.*******;

import com.**.dc.common.result.ResultObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
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.util.Arrays;
import java.util.logging.Logger;

/**
 * @author Ls.
 * @date 2019/11/25 16:30
 */
@Aspect     //Aspect注解代表是一个切面类
@Component  //Component注解代表把此类交给spring来管理
public class LogAspect {
    private static Logger logger = Logger.getLogger(String.valueOf(LogAspect.class));

    /**
     * 这句话是方法切入点
     * 1 execution (* com.my.blog.website.controller..*.*(..))
     * 2 execution : 表示执行
     * 3 第一个*号 : 表示返回值类型, *可以是任意类型
     * 4 com.my.blog.website.controller : 代表扫描的包
     * 5 .. : 代表其底下的子包也进行拦截
     * 6 第二个*号 : 代表对哪个类进行拦截,*代表所有类
     * 7 第三个*号 : 代表方法  *代表任意方法
     * 8 (..) : 代表方法的参数有无都可以
     *
     * 通知执行顺序:
     * (1)没有异常(不会走异常通知)
     *   前置通知->环绕通知之前部分->后置通知(异常不调用)->最终通知(异常也会调用)->环绕通知之后的部分
     * (2)有异常(不会走环绕通知的后半部分和后置通知)
     *   前置通知->环绕通知之前部分->最终通知(异常也会调用)->异常通知
     */
    //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
    @Pointcut("execution( * com.wangyuan.dc.gateway.controller..*.*(..))")  //声明一个切入点
    public void webLog(){}

    //前置通知等可以没有JoinPoint参数  before方法执行之前做的事
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        logger.info("URL : " + request.getRequestURL().toString()
                + ",IP : " + request.getRemoteAddr()
                + ",Method : " + request.getMethod()
                + ",CLASS_METHOD : "+ joinPoint.getSignature().getDeclaringTypeName()
                + "." + joinPoint.getSignature().getName()
                + ",ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }

    //配置后置返回通知(异常发生后不会调用),使用在方法webLog()上注册的切入点
//    @AfterReturning(returning = "object", pointcut = "webLog()")
//    public void doAfterReturning(Object object) throws Throwable {
//        // 处理完请求,返回内容
//        logger.info("RESPONSE :" + object);
//    }
    @AfterReturning(returning = "resultObjectr", pointcut = "webLog()")
    public void logResultVOInfo(ResultObject resultObjectr) throws Exception {
        logger.info("请求结果:" + resultObjectr.getCode() + "\t" + resultObjectr.getMsg());
    }

// 环绕通知(推荐下面这种方式获取方法)
    @Around("webLog()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("----------------环绕通知之前 的部分(注解)----------------");
        // 获取到类名
        String targetName = pjp.getTarget().getClass().getName();
        System.out.println("代理的类是:" + targetName);
        // 获取到参数
        Object[] parameter = pjp.getArgs();
        System.out.println("传入的参数是:" + Arrays.toString(parameter));
        // 获取到方法签名,进而获得方法
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        System.out.println("增强的方法名字是:" + method.getName());
        // 获取参数类型
        Class<?>[] parameterTypes = method.getParameterTypes();
        System.out.println("参数类型是:" + parameterTypes.toString());

        //让方法执行(proceed是拦截的方法的执行返回值,可以针对返回值做一些处理)
        System.out.println("--------------方法开始执行-----------------");
        Object proceed = pjp.proceed();

        //环绕通知之后的业务逻辑部分
        System.out.println("----------------环绕通知之后的部分(注解)----------------");
        return proceed;
    }

    // 异常通知
    @AfterThrowing("webLog()")
    public void afterException() {
        System.out.println("这是异常通知(发生异常后调用)~~~~~~~~~~~(注解)");
    }

    // 最终通知(发生异常也会在最终调用)
    @After("webLog()")
    public void after() {
        System.out.println("这是最终通知(发生异常也会在最终调用)........(注解)");
    }

}