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方法进行日志记录,记录请求的内容、调用的方法、参数以及响应的内容和请求处理的时间。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
3月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
601 3
|
2月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
245 3
|
6月前
|
算法 网络协议 Java
Spring Boot 的接口限流算法
本文介绍了高并发系统中流量控制的重要性及常见的限流算法。首先讲解了简单的计数器法,其通过设置时间窗口内的请求数限制来控制流量,但存在临界问题。接着介绍了滑动窗口算法,通过将时间窗口划分为多个格子,提高了统计精度并缓解了临界问题。随后详细描述了漏桶算法和令牌桶算法,前者以固定速率处理请求,后者允许一定程度的流量突发,更符合实际需求。最后对比了各算法的特点与适用场景,指出选择合适的算法需根据具体情况进行分析。
526 56
Spring Boot 的接口限流算法
|
6月前
|
Java API 网络架构
基于 Spring Boot 框架开发 REST API 接口实践指南
本文详解基于Spring Boot 3.x构建REST API的完整开发流程,涵盖环境搭建、领域建模、响应式编程、安全控制、容器化部署及性能优化等关键环节,助力开发者打造高效稳定的后端服务。
905 1
|
8月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
813 5
|
10月前
|
监控 Java Spring
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
369 16
|
11月前
|
Java 应用服务中间件 Spring
SpringBoot 响应请求是串行还是并行?
Spring Boot 在默认情况下通过 Servlet 容器的线程池实现并行处理 HTTP 请求。通过适当的线程池配置,可以进一步优化并发性能。此外,Spring Boot 提供了异步处理机制(如使用 `@Async` 注解)和反应式编程模型(Spring WebFlux),使得应用能够处理更高的并发负载。在具体项目中,可以根据需求选择合适的处理模型,以充分利用 Spring Boot 的并发处理能力。
375 21
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
239 2
|
Java 开发者 Spring
精通SpringBoot:16个扩展接口精讲
【10月更文挑战第16天】 SpringBoot以其简化的配置和强大的扩展性,成为了Java开发者的首选框架之一。SpringBoot提供了一系列的扩展接口,使得开发者能够灵活地定制和扩展应用的行为。掌握这些扩展接口,能够帮助我们写出更加优雅和高效的代码。本文将详细介绍16个SpringBoot的扩展接口,并探讨它们在实际开发中的应用。
396 1
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
187 0