利用 AOP 记录接口日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 利用 AOP 记录接口日志

常见的小需求

       在我们的后端项目中有很多要调用第三方接口的地方,而调用接口就免不了会因为传递给接口的参数有问题报错,或者对接口的返回值处理不全导致报错或后续的流程有问题。

       对于调试接口通常的做法就是把入参用接口工具向接口地址提交,然后把获取到的返回值和项目中的返回值进行比对。这样来看,在代码中调用接口的入参和调用接口后的返回值对于排错来说就非常重要了。那这样的话,我们可以在每个调用接口地址的前后使用输出日志的方式来记录,就可以得到调用接口的入参和接口的返回值,从而有利于我们以后的调试了。

       我们可以使用 SLF4J 或者 LogBack 等日志框架,在调用接口时来输出一下入参和返回值,大致方法是在调用接口前调用 logger.info 输出入参,然后调用接口后再次调用 logger.info 输出返回值。这样的方式虽然没有问题,但是在每个接口调用前后都要加这样的日志输出代码显得过于麻烦,且不优雅。


简单的解决方法

       在 Spring 框架中为我们提供了 AOP,即面向切面编程。AOP 通过动态代理来管理切面环境,通过反射可以使我们在非侵入的方式下为我们增加前置、后置等方法用来贯穿整个代码层面,从而让我们更加关注业务本身的开发。在 Spring 中的事务就是通过 AOP 来进行管理的,我们这里通过 AOP 完成一个接口调用时打印入参和返回值的功能。

       AOP 有一些名词需要理解,但是不理解这些名词好像又不影响我们实际 AOP 的使用。这些名词包括,切面、通知、引入、切点、连接点和织入。这里我们不讨论这些名词,直接上代码来进行演示。


代码演示

       首先引入依赖,依赖如下:

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency>

       然后,我们来定义一个切面,所谓的切面不过是一个被 @Aspect 注解修饰的类,在类中可以定义一些通知,通知通常包含(前置通知、后置通知、返回通知、异常通知等) ,这里我们定义了前置通知和返回通知。通知是针对切点进行的,切点是用于针对的具体的方法,我们切面类如下:

@Aspect@Component@Slf4jpublicclassTestAspect {
@Pointcut("execution(public * io.coderup2u.xxx.util.yyy.*.*(..))")
publicvoidcontrollerMethod() {}
@Before("controllerMethod()")
publicvoidbefore(JoinPointjoinPoint) {
    }
@AfterReturning(value="controllerMethod()", returning="methodResult")
publicvoidafterReturning(JoinPointjoinPoint, ObjectmethodResult) {
    }
}

       在上面的代码中,使用 @Before 和 @AfterReturning 定义了两个通知,分别是前置通知和返回通知使用 @Pointcut 定义了一个切点,通过 execution 的正则表达式来确定一个连接点(所谓的连接点就是我们实际的业务类),这里 execution 正则表达式的意思是,当执行 io.coderup2u.xxx.util.yyy 下的所有方法时,都会执行切面中的前置通知和返回通知。前置方法是在业务方法执行前被执行,返回通知是在业务方法执行后且没有异常时执行。

       在 before 和 afterReturning 方法中都有一个 JoinPoint 类型的参数,通过该参数可以得到被执行具体方法的名称以及参数,afterReturning 方法的 methodResult 参数可以得到方法执行后的返回值。具体代码如下:

@Pointcut("execution(public * io.coderup2u.xxx.util.yyy.*.*(..))")
publicvoidcontrollerMethod() {}
@Before("controllerMethod()")
publicvoidbefore(JoinPointjoinPoint)
{
MethodSignaturems= (MethodSignature) joinPoint.getSignature();
Methodmethod=ms.getMethod();
longtid=Thread.currentThread().getId();
log.info("===> TID:{} => 准备调用 {} 方法", tid, method.getName());
if (joinPoint.getArgs().length==0) {
return ;
    }
log.info("===> TID:{} => 它的参数如下:", tid);
for (inti=0; i<joinPoint.getArgs().length; i++) {
Objectarg=joinPoint.getArgs()[i];
log.info("===> TID:{} => 第 {} 个参数是:{}", tid, i+1, arg.toString());
    }
}
@AfterReturning(value="controllerMethod()", returning="methodResult")
publicvoidafterReturning(JoinPointjoinPoint, ObjectmethodResult)
{
MethodSignaturems= (MethodSignature) joinPoint.getSignature();
Methodmethod=ms.getMethod();
longtid=Thread.currentThread().getId();
log.info("<=== TID:{} => 方法: {} 的返回值为: {}", tid, method.getName(), methodResult.toString());
}

      最后调用一个接口,来看下 AOP 记录的日志,日志如下:

===>TID:40=>准备调用getAccessToken方法<===TID:40=>方法: getAccessToken的返回值为: {"code":0,"data":{"accessToken":"xxxxxxxxxxxx","expiresIn":7200},"message":"成功"}

       可以看到上面的输出,帮我们输出了线程的 ID,也输出了调用的方法名和方法的返回结果。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
SQL 监控 Java
在IDEA 、springboot中使用切面aop实现日志信息的记录到数据库
这篇文章介绍了如何在IDEA和Spring Boot中使用AOP技术实现日志信息的记录到数据库的详细步骤和代码示例。
在IDEA 、springboot中使用切面aop实现日志信息的记录到数据库
|
3月前
|
Java Spring
在Spring Boot中使用AOP实现日志切面
在Spring Boot中使用AOP实现日志切面
|
28天前
|
Java
日志框架log4j打印异常堆栈信息携带traceId,方便接口异常排查
日常项目运行日志,异常栈打印是不带traceId,导致排查问题查找异常栈很麻烦。
|
2月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之AllLoggers接口获取异常日志的Logger实例的问题如何解决
Java应用结构规范问题之AllLoggers接口获取异常日志的Logger实例的问题如何解决
|
2月前
|
存储 监控 Java
|
2月前
分享一种接口的日志格式
分享一种接口的日志格式
43 13
|
3月前
|
存储 开发框架 前端开发
循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志
循序渐进VUE+Element 前端应用开发(31)--- 系统的日志管理,包括登录日志、接口访问日志、实体变化历史日志
|
22天前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
44 1
|
1月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
【9月更文挑战第9天】AOP(面向切面编程)通过分离横切关注点提高模块化程度,如日志记录、事务管理等。Micronaut AOP基于动态代理机制,在应用启动时为带有特定注解的类生成代理对象,实现在运行时拦截方法调用并执行额外逻辑。通过简单示例展示了如何在不修改 `CalculatorService` 类的情况下记录 `add` 方法的参数和结果,仅需添加 `@Loggable` 注解即可。这不仅提高了代码的可维护性和可扩展性,还降低了引入新错误的风险。
38 13
|
2月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解