方式一:StopWatch手动计时
介绍:Spring、Apache、hutool的工具包中都有手动计时的StopWatch的实现,这里以
org.springframework.util.StopWatch类作为手动计时的实现代码示例
javaimport org.springframework.stereotype.Service; import org.springframework.util.StopWatch; @Service public class UserServiceImpl implements IUserService { @Override public R login(LoginUserReqVO loginUserReqVO) { StopWatch watch = new StopWatch(); watch.start(); // 省略业务操作... watch.stop(); System.out.println("用户登录业务执行耗时:" + watch.getTotalTimeMillis() + "ms"); return R.success(); } }
方式二:AOP统一拦截统计
步骤
添加AOP依赖
xml<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>切面代码
javaimport org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; @Aspect @Component public class TimeConsumingAspect { @Pointcut("execution(* com.zhl.service..*(..))") public void serviceMethods() {} @Around("serviceMethods()") public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable { StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 执行业务方法 Object result = joinPoint.proceed(); stopWatch.stop(); System.out.println("方法【" + joinPoint.getSignature() + "】耗时:" + stopWatch.getTotalTimeMillis() + "ms"); return result; } }
方式三:自定义注解 + AOP统计某些特定的方法
步骤
自定义注解
javaimport java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TimeTracker { String description() default ""; }切面代码
javaimport org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; @Aspect @Component public class TrackTimeAspect { @Around("@annotation(com.zhl.annotation.TimeTracker)") public Object handleTrackTimeMethod(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); TrackTime annotation = signature.getMethod().getAnnotation(TimeTracker.class); String description = annotation.description().isEmpty() ? signature.getMethod().getName() : annotation.description(); StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 执行业务方法 Object result = joinPoint.proceed(); stopWatch.stop(); System.out.println("方法【" + description + "】执行时间:" + stopWatch.getTotalTimeMillis() + "ms"); return result; } }具体使用
javaimport org.springframework.stereotype.Service; @Service public class UserServiceImpl implements IUserService { @Override @TimeTracker(description = "用户登录") public R login(LoginUserReqVO loginUserReqVO) { // 省略业务操作... return R.success(); } }
方式四: 拦截器统计整个接口的耗时性能
步骤
拦截器代码
javaimport org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.*; @Component public class TrackTimeInterceptor implements HandlerInterceptor { private final ThreadLocal<Long> startTime = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) { startTime.set(System.currentTimeMillis()); return true; } @Override public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) { long duration = System.currentTimeMillis() - startTime.get(); System.out.println("接口【" + req.getRequestURI() + "】耗时:" + duration + "ms"); startTime.remove(); } }注册拦截器
javaimport org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.*; @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final TrackTimeInterceptor trackTimeInterceptor; public WebMvcConfig(TrackTimeInterceptor trackTimeInterceptor) { this.trackTimeInterceptor = trackTimeInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(trackTimeInterceptor).addPathPatterns("/api/**"); } }
方式五:过滤器实现
代码示例
javaimport javax.servlet.*; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; import java.io.IOException; @Component public class TrackTimeFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long beginTime = System.currentTimeMillis(); chain.doFilter(request, response); long duration = System.currentTimeMillis() - beginTime; String uri = ((HttpServletRequest) request).getRequestURI(); System.out.println("请求【" + uri + "】总耗时:" + duration + "ms"); } }
TY话:拦截器和过滤器方式的区别
先看二者在tomcat容器中的顺序,客户端请求 → Filter 链 → DispatcherServlet → Interceptor 链 → Controller → 视图渲染 → 返回客户端
)二者区别
过滤器 拦截器 规范 Servlet规范,是JavaEE标准组件,与框架无关,直接由Servlet容器(如Tomcat)管理 是SpringMVC的组件,依赖于Spring容器 作用范围 拦截所有HTTP请求(包括静态资源、未映射到Controller的请求) 仅拦截映射到Controller的请求(需经过DispatcherServlet) 统计范围 从进入Servlet容器到响应返回客户端,涵盖整个处理链路(包括Filter链、Interceptor链、Controller执行、视图渲染等) 覆盖Controller方法执行、参数解析、返回值处理 适用场景 适合处理通用问题(如编码设置、全局日志、安全过滤) 更适合Controller相关的横切逻辑(如权限校验、耗时统计、参数预处理)
方式六:Actuator + Micrometer + Prometheus,专业的事交给专业的工具干
- 详情移步到 springboot实现应用监控方案
方式七:实现Spring事件 ServletRequestHandledEvent
代码示例
javaimport org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import org.springframework.web.context.request.ServletRequestHandledEvent; @Component public class CustomServletRequestHandledEvent implements ApplicationListener<ServletRequestHandledEvent> { @Override public void onApplicationEvent(ServletRequestHandledEvent event) { System.out.println("请求【" + event.getRequestUrl() + "】处理时长:" + event.getProcessingTimeMillis() + "ms"); } }
几种方式的对比
| 方式 | 优点 | 缺点 | 场景推荐 |
|---|---|---|---|
| StopWatch手动计时 | 无需配置、上手简单 | 代码侵入性强,不适合全局使用 | 临时测试 |
| AOP统一拦截统计 | 代码无侵入、集中管理 | 粒度控制弱,不适合监控某个别方法 | 后端业务层整体监控 |
| 自定义注解 + AOP | 可控性高、便于扩展 | 方法需要手动打注解 | 对关键方法监控 |
| 拦截器实现 | Web接口性能监控利器 | 无法统计后端业务层逻辑耗时 | Web接口性能分析 |
| 过滤器实现 | 可以统计整个链路 | 无法统计后端业务层逻辑耗时 | 网关、统一入口 |
| 集成第三方中间件 | 适合线上 | 有上手门槛 | 生产环境实时监控 |
| Spring事件 | 代码无侵入、自动触发 | 无法统计后端业务层逻辑耗时 | 接口的简易请求分析 |