java应用中记录http请求耗时推荐用spring拦截器(精准controller层)或servlet filter(覆盖全链路);拦截器需实现handlerinterceptor,在prehandle存起始时间、aftercompletion计算差值;filter应继承onceperrequestfilter,在dofilterinternal的finally块中统计并打印耗时,建议用system.nanotime()和mdc增强日志可追溯性。

在 Java 应用中记录 HTTP 请求耗时,核心思路是:在请求开始前记录时间戳,响应返回后再计算差值并打印。常用方式有 Filter(Servlet 容器)、Spring Interceptor(Spring MVC) 或 WebMvcConfigurer + HandlerInterceptor,对 Spring Boot 项目推荐使用拦截器,更轻量、更可控。
使用 Spring 拦截器记录请求耗时
适合 Spring Boot / Spring MVC 项目,能精准捕获 Controller 层处理前后的耗时(不含静态资源、异常中断等情况)。
- 实现
HandlerInterceptor接口,在preHandle中存入开始时间(如放入ThreadLocal或RequestAttributes) - 在
afterCompletion中取出开始时间,与当前时间做差,打印日志(建议用StopWatch或System.nanoTime()提升精度) - 注意:避免在
postHandle中计算,因它不保证执行(比如异常未被捕获)
使用 Servlet Filter 记录完整链路耗时
比拦截器更底层,可覆盖所有进入容器的请求(包括静态资源、错误页等),适合统计端到端真实耗时。
- 继承
OncePerRequestFilter(避免重复执行),重写doFilterInternal - 在
chain.doFilter()前记录System.currentTimeMillis()或System.nanoTime() - 在
finally块中计算耗时并打印,确保即使发生异常也能记录 - 可结合 MDC(Mapped Diagnostic Context)为每条日志添加 traceId,方便关联上下文
日志格式与关键细节
耗时日志应包含必要字段,便于排查和监控:
-
HTTP 方法 + 路径:如
GET /api/users -
状态码:从
HttpServletResponse获取,注意异步或转发可能影响获取时机 -
耗时(毫秒/微秒):推荐用
System.nanoTime()避免系统时间调整干扰 -
客户端 IP:从
HttpServletRequest.getRemoteAddr()或X-Forwarded-For头获取 - 可选:User-Agent、traceId、请求体大小(谨慎开启)
简单示例(Filter 版)
以下代码片段可直接集成到 Spring Boot 项目中:
public class TimingFilter extends OncePerRequestFilter {
private static final Logger log = LoggerFactory.getLogger(TimingFilter.class);
<pre class="brush:java;toolbar:false;">@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
long start = System.nanoTime();
try {
filterChain.doFilter(request, response);
} finally {
long costMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
String method = request.getMethod();
String uri = request.getRequestURI();
int status = response.getStatus();
log.info("{} {} {} - {}ms", method, uri, status, costMs);
}
}}
再通过 @Bean 注册该 Filter 即可生效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











