AOP实现日志记录需求

首先创建annotation包,包下创建SystemLog类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SystemLog {

    String businessName();
}

创建aspect包,包下创建LogAspect类

@Component
@Aspect
@Slf4j
public class LogAspect {

    @Pointcut("@annotation(com.zzq.annotation.SystemLog)")
    public void pt() {

    }

    @Around("pt()")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {

        Object ret ;
        try {
            handleBefore(joinPoint);
            ret = joinPoint.proceed();
            handleAfter(ret);
        } finally {
            //结束后换行
            log.info("=======End=======" + System.lineSeparator());


        }

        return ret;
    }

    private void handleAfter(Object ret) {
        // 打印出参
        log.info("Response      : {}",JSON.toJSONString(ret) );
    }

    private void handleBefore(ProceedingJoinPoint joinPoint) {


        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        //获取被增强方法上的注解对象
        SystemLog systemLog = getSystemLog(joinPoint);


        log.info("======= Start =======");
        // 打印请求 URL,增加空格使"URL:"和URL之间有一定间隔
        log.info("URL          : {}", request.getRequestURL());
        // 打印描述信息,同样增加空格
        log.info("BusinessName : {}", systemLog.businessName());
        // 打印 Http method,由于"HTTP Method"较长,可能需要更多空格来对齐
        log.info("HTTP Method  : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法,确保类名和方法名之间有适当的空格
        log.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP           : {}", request.getRemoteHost());
        // 打印请求入参,如果参数较多或格式复杂,可能需要检查JSON.toJSONString的输出格式
        log.info("Request Args : {}", JSON.toJSONString(joinPoint.getArgs()));

    }

    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        SystemLog systemLog = methodSignature.getMethod().getAnnotation(SystemLog.class);
        return systemLog;
    }
}

@Component: 这个注解表明 LogAspect 是一个 Spring 组件,Spring 容器会管理这个类的实例。在 Spring AOP 中,这通常意味着这个类会被 Spring 自动检测和注册为一个切面(Aspect)。

@Aspect: 这个注解表明 LogAspect 是一个切面类,它定义了一个或多个通知(Advice)和切点(Pointcut)。切面类负责将通知织入到目标对象中。

@Slf4j: 这是 Lombok 库提供的一个注解,用于自动生成一个名为 log 的日志对象,该对象通常是 org.slf4j.Logger 类型。这使得在类中的任何地方都可以直接使用 log 对象进行日志记录。

@Pointcut(“@annotation(com.zzq.annotation.SystemLog)”): 这个注解定义了一个切点表达式,它指定了哪些方法应该被增强。具体来说,任何被@com.zzq.annotation.SystemLog 注解标记的方法都将被这个切点捕获。pt() 方法本身没有实现体,它只是作为一个切点表达式的声明。
环绕通知(Around Advice)
@Around(“pt()”): 这个注解定义了一个环绕通知,它会在目标方法执行之前和之后执行。环绕通知接收一个 ProceedingJoinPoint 参数,这个参数代表了目标方法的执行点。通过调用 joinPoint.proceed(),可以执行目标方法,并获取其返回值。
printLog 方法是环绕通知的实现。它首先尝试执行 handleBefore 方法来记录一些前置信息(如请求的 URL、HTTP 方法、类名和方法名等),然后调用 joinPoint.proceed() 来执行目标方法,并将返回值存储在 ret 变量中。之后,它调用 handleAfter 方法来记录后置信息(如响应结果)。无论目标方法是否成功执行,finally 块中的代码都会执行,以记录日志的结束标记。

handleBefore 方法:这个方法在目标方法执行之前被调用,用于记录请求的相关信息,如请求的 URL、HTTP 方法、IP 地址、请求参数以及业务名称(从 @SystemLog 注解中获取)。

handleAfter 方法:这个方法在目标方法执行之后被调用,用于记录响应结果。它使用 JSON.toJSONString(ret) 将响应结果转换为 JSON 字符串,并记录到日志中。

getSystemLog 方法:这个方法用于从目标方法上获取 @SystemLog 注解实例。它通过 joinPoint.getSignature() 获取到 MethodSignature,然后调用 getMethod() 获取到 Method 对象,最后从该对象上获取注解实例。

最后在方法中加入中

在这里插入图片描述

最后效果展示

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值