Spring AOP怎么实现打印HTTP接口出入参日志

发布时间:2022-09-28 14:46:48 作者:iii
来源:亿速云 阅读:234

Spring AOP怎么实现打印HTTP接口出入参日志

在现代的Web应用开发中,日志记录是一个非常重要的环节。特别是在调试和排查问题时,能够清晰地看到每个HTTP接口的入参和出参是非常有帮助的。Spring AOP(Aspect-Oriented Programming,面向切面编程)提供了一种优雅的方式来实现这一需求。本文将详细介绍如何使用Spring AOP来实现打印HTTP接口的入参和出参日志。

1. Spring AOP简介

Spring AOP是Spring框架中的一个模块,它允许开发者通过切面(Aspect)来模块化横切关注点(Cross-cutting Concerns)。横切关注点是指那些在应用程序中多个模块中重复出现的功能,例如日志记录、事务管理、安全性等。

Spring AOP通过代理模式来实现切面,主要有两种代理方式:

2. 实现打印HTTP接口出入参日志的步骤

2.1 添加依赖

首先,我们需要在项目中添加Spring AOP的依赖。如果你使用的是Maven项目,可以在pom.xml中添加以下依赖:

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

2.2 创建切面类

接下来,我们需要创建一个切面类,用于定义在HTTP接口调用前后执行的逻辑。切面类通常使用@Aspect注解进行标记。

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    // 定义切点,匹配所有Controller中的方法
    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void controllerMethods() {}

    // 在方法执行前打印入参
    @Before("controllerMethods()")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        logger.info("Entering method: {}, with arguments: {}", methodName, args);
    }

    // 在方法执行后打印出参
    @AfterReturning(pointcut = "controllerMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Exiting method: {}, with result: {}", methodName, result);
    }
}

2.3 配置AOP

在Spring Boot项目中,AOP默认是启用的,因此我们不需要额外的配置。如果你使用的是非Spring Boot项目,可以在Spring配置文件中启用AOP:

<aop:aspectj-autoproxy/>

2.4 测试切面

现在,我们可以编写一个简单的Controller来测试我们的切面是否正常工作。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @GetMapping("/hello")
    public String sayHello(@RequestParam String name) {
        return "Hello, " + name;
    }
}

启动应用程序并访问/hello接口,你将会在控制台中看到类似以下的日志输出:

Entering method: sayHello, with arguments: [John]
Exiting method: sayHello, with result: Hello, John

2.5 处理复杂对象

在实际开发中,HTTP接口的入参和出参可能是复杂的对象。为了能够更好地打印这些对象,我们可以使用JSON格式来序列化它们。

首先,我们需要添加Jackson依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

然后,修改切面类中的日志记录逻辑:

import com.fasterxml.jackson.databind.ObjectMapper;

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void controllerMethods() {}

    @Before("controllerMethods()")
    public void logBefore(JoinPoint joinPoint) throws JsonProcessingException {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String argsJson = objectMapper.writeValueAsString(args);
        logger.info("Entering method: {}, with arguments: {}", methodName, argsJson);
    }

    @AfterReturning(pointcut = "controllerMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) throws JsonProcessingException {
        String methodName = joinPoint.getSignature().getName();
        String resultJson = objectMapper.writeValueAsString(result);
        logger.info("Exiting method: {}, with result: {}", methodName, resultJson);
    }
}

现在,日志输出将会以JSON格式显示复杂对象的详细信息。

2.6 处理异常情况

在实际应用中,HTTP接口可能会抛出异常。为了能够记录异常信息,我们可以使用@AfterThrowing注解来定义一个切面方法,用于在方法抛出异常时执行。

import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void controllerMethods() {}

    @Before("controllerMethods()")
    public void logBefore(JoinPoint joinPoint) throws JsonProcessingException {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String argsJson = objectMapper.writeValueAsString(args);
        logger.info("Entering method: {}, with arguments: {}", methodName, argsJson);
    }

    @AfterReturning(pointcut = "controllerMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) throws JsonProcessingException {
        String methodName = joinPoint.getSignature().getName();
        String resultJson = objectMapper.writeValueAsString(result);
        logger.info("Exiting method: {}, with result: {}", methodName, resultJson);
    }

    @AfterThrowing(pointcut = "controllerMethods()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        String methodName = joinPoint.getSignature().getName();
        logger.error("Exception in method: {}, with message: {}", methodName, ex.getMessage());
    }
}

2.7 优化日志输出

在实际生产环境中,日志输出可能会非常庞大。为了减少日志的冗余,我们可以通过条件判断来决定是否记录日志。例如,只有在调试模式下才记录详细的入参和出参信息。

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void controllerMethods() {}

    @Before("controllerMethods()")
    public void logBefore(JoinPoint joinPoint) throws JsonProcessingException {
        if (logger.isDebugEnabled()) {
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            String argsJson = objectMapper.writeValueAsString(args);
            logger.debug("Entering method: {}, with arguments: {}", methodName, argsJson);
        }
    }

    @AfterReturning(pointcut = "controllerMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) throws JsonProcessingException {
        if (logger.isDebugEnabled()) {
            String methodName = joinPoint.getSignature().getName();
            String resultJson = objectMapper.writeValueAsString(result);
            logger.debug("Exiting method: {}, with result: {}", methodName, resultJson);
        }
    }

    @AfterThrowing(pointcut = "controllerMethods()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        String methodName = joinPoint.getSignature().getName();
        logger.error("Exception in method: {}, with message: {}", methodName, ex.getMessage());
    }
}

3. 总结

通过Spring AOP,我们可以非常方便地实现HTTP接口的入参和出参日志记录。本文详细介绍了如何使用Spring AOP来创建切面类,并在HTTP接口调用前后记录日志。我们还讨论了如何处理复杂对象和异常情况,并提供了优化日志输出的建议。

在实际开发中,日志记录是一个非常重要的环节,能够帮助我们快速定位和解决问题。通过本文的介绍,希望读者能够掌握如何使用Spring AOP来实现这一功能,并在实际项目中加以应用。

推荐阅读:
  1. Spring AOP实现系统日志功能
  2. Spring+Http请求+HttpClient实现传参

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring aop http

上一篇:Oracle怎么删除大量表记录

下一篇:react router如何使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》