SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间

简介: SpringBoot集成AOP实现每个接口请求参数和返回参数并记录每个接口请求时间

代码主要目的是controller方法进行日志记录,记录请求的内容、调用的方法、参数以及响应的内容和请求处理的时间。

1.介绍

AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的一个重要特性,允许开发者定义跨多个对象的横切关注点。

在Spring Boot中,AOP的使用几个步骤:

  1. 定义Aspect:Aspect是包含一些advice(通知)的类。通知是实际执行的代码,它可以是一个方法或者一个lambda表达式。在Aspect中,你可以定义前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)等。
  2. 配置AspectJ自动代理
  3. 定义Pointcut表达式:Pointcut表达式定义了通知何时执行。你可以通过定义方法签名、类名、包名等来定义Pointcut表达式。
package com.up.cloud.core.aspect;
 
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;
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;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
 
/**
 * @author liu pei
 * @date 2023年11月24日 下午7:12
 * @Description:
 */
@Aspect
@Component
public class AccessLogAspect {
    private static final Logger log = LoggerFactory.getLogger(AccessLogAspect.class);
 
    /**
     * 起始时间的时间戳
     */
    private static final ThreadLocal<Long> START_TIME = new ThreadLocal<>();
 
    @Pointcut("execution(public * com.up.cloud.*.controller..*.*(..)) || execution(public * com.up.cloud.server.*.controller..*.*(..))")
    public void invokeLog() {
        // do something
    }
 
    @Before("invokeLog()")
    public void doBefore(JoinPoint joinPoint) {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        //String args = Arrays.toString(joinPoint.getArgs());
        StringUtils.join(joinPoint.getArgs(),"");
        log.info(" Request URL : [{}, {}]", request.getMethod(), request.getRequestURL());
        log.info(" Class : [{}] , Method : [{}()]", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        log.info(" Request Param : {}", JSONUtil.toJsonStr(joinPoint.getArgs()));
        START_TIME.set(System.currentTimeMillis());
 
    }
 
    @AfterReturning(returning = "ret", pointcut = "invokeLog()")
    public void doAfterReturning(Object ret) {
        // 处理完请求,返回内容
        String jsonStr = JSONUtil.parseObj(ret).toString();
        log.info(" Response Body : {}", jsonStr.length() > 500 ? jsonStr.substring(0, 499) : jsonStr);
        log.info(" Response Time : {} ms ", (System.currentTimeMillis() - START_TIME.get()));
 
        START_TIME.remove();
    }
}

2.代码解释:

在AspectJ的AOP(面向切面编程)中,execution是一个特殊的Pointcut Designator (PDC)。它用于匹配方法的执行。
 
在给定的代码中:
 
java
@Pointcut("execution(public * com.up.cloud.*.controller..*.*(..)) || execution(public * com.up.cloud.server.*.controller..*.*(..))")  
public void invokeLog() {  
    // do something  
}
意思是匹配com.up.cloud`包及其子包下的所有public方法的执行。
其中:
 
 
*:表示方法名,第一个*表示方法名的第一个字符可以是任何字符,
第二个*表示方法名的第二个字符也可以是任何字符,
第三个*表示方法名的第三个字符可以是任何字符。
所以,.*(...)可以匹配任何方法名。
com.up.cloud.*.controller..*:表示类名。
第一个*表示com.up.cloud下的任意子包名,
第二个*表示该子包下的任意类名,第三个和第四个*分别表示类名的第二和第三个字符可以是任意字符。
所以,.controller..*可以匹配所有以controller结尾的类名。
这个Pointcut会匹配所有在com.up.cloud和com.up.cloud.server包及其子包下的
public controller类的方法执行。
 
简单地说,execution表示匹配某个方法的执行。

3.整体代码介绍

用于记录请求和响应的日志。

  1. 定义AspectAccessLogAspect 是一个Aspect,它包含了前置通知(Before)、后置通知(AfterReturning)功能。
  2. Pointcut定义:通过 @Pointcut 注解定义了一个切入点表达式,用于匹配com.up.cloudcom.up.cloud.server包下的所有public controller方法。
  3. 前置通知(Before)
  • @Before("invokeLog()"):在匹配到切入点的方法执行之前,执行前置通知的方法。
  • doBefore 方法中,首先获取了当前的请求信息,并记录了请求的URL、调用的类和方法以及请求参数。
  • 同时,还记录了当前的时间戳,用于后续计算请求处理时间。
  1. 后置通知(AfterReturning)
  • @AfterReturning(returning = "ret", pointcut = "invokeLog()"):在匹配到切入点的方法执行之后且在返回结果之前,执行后置通知的方法。
  • doAfterReturning 方法中,首先将返回的结果转换为JSON字符串并记录下来。
  • 计算并记录了请求处理的时间。
  • 最后清除了之前记录的起始时间。
  1. 日志记录:使用SLF4J的Logger来记录日志,记录了请求的URL、方法、参数以及响应的内容和请求处理的时间。
  2. 线程局部变量:使用 ThreadLocal 来存储起始时间,这样每个线程的起始时间都是独立的,不会互相干扰。

代码主要目的是对controller方法进行日志记录,记录请求的内容、调用的方法、参数以及响应的内容和请求处理的时间。

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
5月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
786 3
|
7月前
|
缓存 监控 安全
电商API集成入门:从零开始搭建高效接口
在数字化电商时代,API集成成为企业提升效率、实现系统互联的关键。本文从零开始,逐步讲解如何搭建高效、可靠的电商API接口,适合初学者学习。内容涵盖API基础、认证安全、请求处理、性能优化等核心步骤,并提供Python代码示例与数学公式辅助理解。通过实践,读者可掌握构建优质电商API的技巧,提升用户体验与系统性能。
330 0
|
8月前
|
算法 网络协议 Java
Spring Boot 的接口限流算法
本文介绍了高并发系统中流量控制的重要性及常见的限流算法。首先讲解了简单的计数器法,其通过设置时间窗口内的请求数限制来控制流量,但存在临界问题。接着介绍了滑动窗口算法,通过将时间窗口划分为多个格子,提高了统计精度并缓解了临界问题。随后详细描述了漏桶算法和令牌桶算法,前者以固定速率处理请求,后者允许一定程度的流量突发,更符合实际需求。最后对比了各算法的特点与适用场景,指出选择合适的算法需根据具体情况进行分析。
723 56
Spring Boot 的接口限流算法
|
8月前
|
前端开发
SpringBoot2.3.1集成Knife4j接口文档
SpringBoot2.3.1集成Knife4j接口文档
889 44
|
7月前
|
JSON 分布式计算 大数据
springboot项目集成大数据第三方dolphinscheduler调度器
springboot项目集成大数据第三方dolphinscheduler调度器
450 3
|
7月前
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
681 0
第07课:Spring Boot集成Thymeleaf模板引擎
|
7月前
|
Java 关系型数据库 MySQL
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
751 2
|
7月前
|
分布式计算 Java 大数据
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
417 2
|
7月前
|
安全 数据安全/隐私保护
SAP集成HTTP接口(x-www-form-urlencoded格式)
实现这一过程时,务必遵循最佳实践,包括确保代码的稳定性、考虑到异常处理和系统资源的优化使用。这样做不仅能确保数据的安全和有效性,还能提高系统集成的效率和可靠性。
508 4