SpringBoot 统计API接口用时该使用过滤器还是拦截器?

统计请求的处理时间(用时)既可以使用 Servlet 过滤器(Filter),也可以使用 Spring 拦截器(Interceptor)。两者都可以在请求处理前后插入自定义逻辑,从而实现对请求响应时间的统计。

使用建议

如果你需要在更底层、与框架无关的地方记录所有请求(包括静态资源请求)的处理时间,那么 Servlet 过滤器是一个更好的选择。

如果你正在使用 Spring MVC 并且关注的是 Controller 层的处理时间,或者需要访问到 Spring 上下文中的服务,那么 Spring 拦截器可能更为合适。

代码样例

Servlet 过滤器(Filter)

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.Instant;

// @Component 注册时会new 这里无需指定 registration.setFilter(new LogFilter());
@Slf4j
public class LogFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.err.println("***LogFilter.doFilter.start***");
        HttpServletRequest httpReq = (HttpServletRequest) request;
        long startTime = Instant.now().toEpochMilli();

        // 记录请求开始时间及请求信息
        log.warn("LogFilter.doFilter: Start processing request at {} - {}", Instant.now(), httpReq.getRequestURI());

        try {
            // 将请求传递给下一个过滤器或目标资源
            chain.doFilter(request, response);
        } finally {
            // 记录请求结束时间及响应状态码
            long endTime = Instant.now().toEpochMilli();
            int statusCode = ((HttpServletResponse) response).getStatus();
            log.warn("LogFilter.doFilter: Finished processing request at {} - {} in {} ms. Status code: {}", Instant.now(), httpReq.getRequestURI(), (endTime - startTime), statusCode);
        }
        System.err.println("***LogFilter.doFilter.end***");
    }
}

注册过滤器(Filter)

@Configuration
public class AppConfig {
    @Bean
    public FilterRegistrationBean<LogFilter> tokenFilterRegistration() {
        FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new LogFilter());
        // 可以设置过滤器名称
        registration.setName("logFilter");
        // 设置拦截规则
        registration.addUrlPatterns("/*"); // 拦截所有请求
        // 设置过滤器执行顺序,默认为0,数值越小优先级越高
        registration.setOrder(1);
        return registration;
    }
}

Spring 拦截器(Interceptor)

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.time.Instant;

@Component
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.err.println("***LogInterceptor.preHandle***");
        long startTime = Instant.now().toEpochMilli();
        request.setAttribute("startTime", startTime);
        log.warn("LogInterceptor.postHandle: Start processing request at {} - {}", Instant.now(), request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.err.println("***LogInterceptor.preHandle***");
        // 获取请求开始时间
        Long startTime = (Long) request.getAttribute("startTime");
        if (startTime != null) {
            long executionTime = Instant.now().toEpochMilli() - startTime;
            int statusCode = response.getStatus();
            log.warn("LogInterceptor.postHandle: Finished processing request at {} - {} in {} ms. Status code: {}", Instant.now(), request.getRequestURI(), executionTime, statusCode);
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.err.println("***LogInterceptor.afterCompletion***");
        // 在此可以添加额外的后处理逻辑,但本例中我们不需要
    }
}

注册拦截器(Interceptor)

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ResponsePostInterceptor responsePostInterceptor;
    @Autowired
    private LogInterceptor logInterceptor;

    /**
     * 为拦截器注册表添加拦截器
     *
     * @param registry 拦截器注册表
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 在Spring MVC配置中注册一个名为responsePostInterceptor的拦截器,使其能够对匹配路径“/**”(即对应用程序中的所有路径)的请求进行拦截
        registry.addInterceptor(responsePostInterceptor).addPathPatterns("/**");
        registry.addInterceptor(logInterceptor).addPathPatterns("/**");
    }
}

[Ref] 在Spring Boot中注册过滤器几种方式

测试验证

在这里插入图片描述

在这里插入图片描述

# 过滤器开始计时
***LogFilter.doFilter.start***
[2024-01-17 08:17:55] [WARN ] [http-nio-8080-exec-2] [LogFilter.java:22][LogFilter.doFilter: Start processing request at 2024-01-17T00:17:55.662652400Z - /students]
***RequestHeaderCheckFilter.doFilter.start***

# 拦截器组的 preHandle
***ResponsePostInterceptor.preHandle***
# log用时拦截器开始计时
***LogInterceptor.preHandle***
[2024-01-17 08:17:55] [WARN ] [http-nio-8080-exec-2] [LogInterceptor.java:20][LogInterceptor.postHandle: Start processing request at 2024-01-17T00:17:55.852229500Z - /students]

# Controller层
***StudentController.edit***
[2024-01-17 08:17:56] [INFO ] [http-nio-8080-exec-2] [HikariDataSource.java:110][practisedb - Starting...]
[2024-01-17 08:17:56] [INFO ] [http-nio-8080-exec-2] [HikariPool.java:565][practisedb - Added connection com.mysql.cj.jdbc.ConnectionImpl@34a6ebfc]
[2024-01-17 08:17:56] [INFO ] [http-nio-8080-exec-2] [HikariDataSource.java:123][practisedb - Start completed.]

# @ControllerAdvice对Response增强,比如修改状态码,补充header值
***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***

# 拦截器组的 postHandle
***LogInterceptor.postHandle***
# log用时拦截器结束计时
[2024-01-17 08:17:56] [WARN ] [http-nio-8080-exec-2] [LogInterceptor.java:32][LogInterceptor.postHandle: Finished processing request at 2024-01-17T00:17:56.636557900Z - /students in 784 ms. Status code: 200]
***ResponsePostInterceptor.postHandle***

# 拦截器组的 afterCompletion
***LogInterceptor.afterCompletion***
***ResponsePostInterceptor.afterCompletion***

# 过滤器结束计时
***RequestHeaderCheckFilter.doFilter.end***
[2024-01-17 08:17:56] [WARN ] [http-nio-8080-exec-2] [LogFilter.java:31][LogFilter.doFilter: Finished processing request at 2024-01-17T00:17:56.920165800Z - /students in 1258 ms. Status code: 200]
***LogFilter.doFilter.end***

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/330368.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

汽车芯片「新变量」

编者按&#xff1a;汽车行业的格局重构和技术革新&#xff0c;也在推动芯片赛道进入变革周期。不同商业模式的博弈&#xff0c;持续升温。 对于智能汽车来说&#xff0c;过去几年经历了多轮硬件和软件的性能迭代&#xff0c;甚至是革新&#xff0c;如今&#xff0c;市场正在进…

张驰咨询:六西格玛工具企业如何实现资源优化与效率最大化

在这个百年未有之大变局的时期&#xff0c;我们面临着前所未有的挑战与机遇。我一直在寻找提升效率&#xff0c;减少资源浪费的方法。而六西格玛培训提供了一个系统化的解决方案&#xff0c;它不仅是一套工具&#xff0c;更是一种精益思维。 让我们一起思考一个问题&#xff1a…

VMware workstation安装SUSE Linux Enterprise Server 12 SP5虚拟机并配置网络

VMware workstation安装SUSE Linux Enterprise Server 12 SP5虚拟机并配置网络 SUSE Linux Enterprise Server是企业级Linux系统&#xff0c;适合企业应用。该文档适用于在VMware workstation平台安装SUSE Linux Enterprise Server虚拟机。 1.安装准备 1.1安装平台 Windows…

设计一个网页爬虫

定义 User Case 和 约束 注意&#xff1a;没有一个面试官会阐述清楚问题&#xff0c;我们需要定义Use case和约束 Use cases 我们的作用域只是处理以下Use Case&#xff1a; Service 爬取一批 url 生成包含搜索词的单词到页面的反向索引给页面生成标题和片段– 标题和片段是…

【机器学习】机器学习变量分析第02课

当我们谈论用机器学习来预测咖啡店的销售额时&#xff0c;我们实际上是在处理一系列与咖啡销售相关的变量。这些变量就像是我们用来理解销售情况的“线索”或“指标”。那么&#xff0c;让我们用通俗易懂的方式来聊聊这些变量是怎么工作的。 特征变量&#xff1a;咖啡店的“档…

Spring MVC学习之——自定义日期转化器

日期转换器 在数据库中的日期数据是date类型&#xff0c;而如何我们想在页面自己添加数据&#xff0c;一般是使用年-月-日的形式&#xff0c;这种形式不仅date类型接收不到&#xff0c;而且传来的是String类型&#xff0c;此时&#xff0c;我们就可以自定义日期转换器来接收数…

JVM知识总结

1.概述 JVM指的是Java虚拟机&#xff0c;本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件&#xff0c;作用是为了支持跨平台特性。 功能&#xff1a; 装载字节码&#xff0c;解释/编译为机器码 管理数据存储和垃圾回收 优化热点代码提升效率 …

【数学建模】2024年华数杯国际赛B题-光伏发电Photovoltaic Power 思路、代码、参考论文

1 问题背景 中国电力构成包括传统能源(如煤炭、石油、天然气)、可再生能源(如水电、风能、太阳能、核能)和其他形式的电力。这些发电模式在满足中国巨大的电力需求方面发挥着至关重要的作用。据最新数据显示&#xff0c;中国总发电量超过20万亿千瓦时&#xff0c;居世界第一。…

【征服redis8】Redis的AOF持久化

Redis 支持多种持久化方式来保证数据的可靠性和持久性。前面我们介绍了RDB方式。我们我们介绍第二种方式——AOF&#xff08;Append Only File&#xff09;机制是一种常用的持久化方式&#xff0c;它记录了所有对 Redis 数据库进行修改的命令&#xff0c;在 Redis 重启时可以使…

echarts X轴数据过多导致重叠展示不全问题(已解决)

问题 x轴数据过多导致坐标轴数据重叠 修改后 List item interval为0代表每个标签都显示&#xff0c;即间隔为0&#xff01; 将其设置为我们想要的数值即可。 xAxis: {type: "time",splitLine: {show: false,},axisLine: {show: false,lineStyle: {color: &qu…

Spring MVC学习——解决请求参数中文乱码

解决请求参数中文乱码问题 1.POST请求方式解决乱码问题 在web.xml里面设置编码过滤器 <filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><…

lua使用resty.http做nginx反向代理(https请求,docker容器化部署集群),一个域名多项目转发

下载使用 链接&#xff1a;https://pan.baidu.com/s/1uQ7yCzQsPWsF6xavFTpbZg 提取码&#xff1a;htay –来自百度网盘超级会员V5的分享 在根目录下执行: # 从 github 上下载文件 git clone https://github.com/ledgetech/lua-resty-http.git # 将 lua-resty-http/lib/ 下的 r…

客户案例 | 思腾合力助力某能源公司地质数据智能化计算平台建设

助力某能源公司 地质数据智能化计算平台建设 石油行业是全球最大的行业之一&#xff0c;涉及到从地下或海底开采原油和天然气的勘探、开发、生产、运输、精炼和销售的全过程。石油不仅是世界上最主要的能源之一&#xff0c;还是化工产品的主要原料。石油行业的运作对全球经济有…

Java多线程并发篇----第二十篇

系列文章目录 文章目录 系列文章目录前言一、拒绝策略二、Java 线程池工作过程三、JAVA 阻塞队列原理前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、拒绝策略…

VS代码生成工具ReSharper v2023.3正式发布——支持C# 12

实质上&#xff0c;ReSharper特征可用于C#&#xff0c;VB.net&#xff0c;XML&#xff0c;Asp.net&#xff0c;XAML&#xff0c;和构建脚本。 使用ReSharper&#xff0c;你可以进行深度代码分析&#xff0c;智能代码协助&#xff0c;实时错误代码高亮显示&#xff0c;解决方案范…

AI-数学-高中-6-求分式函数值域(y的取值范围)

原作者视频&#xff1a;函数】4分式函数的值域&#xff08;易&#xff09;_哔哩哔哩_bilibili 1.一次比一次&#xff1a;分数函数&#xff0c;分子与分母都是1次。 1.1 画xy轴图&#xff0c;计算垂直渐近线移动数值、画出渐近线&#xff1a;用分母不能为0来计算&#xff0c;如…

1739. 迷宫的所有路径-深度优先搜索-DFS

代码&#xff1a; #include<bits/stdc.h> using namespace std; int n; int fx[4]{0,1,0,-1}; int fy[4]{1,0,-1,0}; bool vis[100][100]; int q[35][3]; int c; void print(int k){c;cout<<c<<":";for(int i1;i<k;i){cout<<q[i][1]<…

TypeError: strip_name() got an unexpected keyword argument ‘many‘问题的解决

引言 在读一本书《Learn Python Programming》1的第8章&#xff0c;按照书中的讲解先后安装了marshmallow和pytest第三方库&#xff0c;j进而按照书中的代码结构和代码在ch08文件夹下运行pytest tests&#xff0c;出现如下错误&#xff1a; ch08中的api.py的代码为&#xff1…

Qt/QML编程之路:Grid、GridLayout、GridView、Repeater(33)

GRID网格用处非常大,不仅在excel中,在GUI中,也是非常重要的一种控件。 Grid 网格是一种以网格形式定位其子项的类型。网格创建一个足够大的单元格网格,以容纳其所有子项,并将这些项从左到右、从上到下放置在单元格中。每个项目都位于其单元格的左上角,位置为(0,0)。…

K8s-架构

一、K8s节点划分 K8s集群包含Master(控制节点)和Node(工作节点)&#xff0c;应用部署在Node节点上。 集群架构图&#xff1a; 二、Master节点 Master节点分成四个组件&#xff1a;scheduler、ApiServer、Controller Manager、ETCD。类似三层结构&#xff0c;controller&#…