Skip to content

方式一:StopWatch手动计时

  • 介绍:Spring、Apache、hutool的工具包中都有手动计时的StopWatch的实现,这里以 org.springframework.util.StopWatch 类作为手动计时的实现

  • 代码示例

    java
    import 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统一拦截统计

  • 步骤

    1. 添加AOP依赖

      xml
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
    2. 切面代码

      java
      import 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统计某些特定的方法

  • 步骤

    1. 自定义注解

      java
      import java.lang.annotation.*;
      
      
      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface TimeTracker {
          String description() default "";
      }
    2. 切面代码

      java
      import 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;
          }
      }
    3. 具体使用

      java
      import org.springframework.stereotype.Service;
      
      @Service
      public class UserServiceImpl implements IUserService {
      
          @Override
          @TimeTracker(description = "用户登录")
          public R login(LoginUserReqVO loginUserReqVO) {
              // 省略业务操作...
              
              return R.success();
          }
      }

方式四: 拦截器统计整个接口的耗时性能

  • 步骤

    1. 拦截器代码

      java
      import 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();
          }
      }
    2. 注册拦截器

      java
      import 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/**");
          }
      }

方式五:过滤器实现

  • 代码示例

    java
    import 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,专业的事交给专业的工具干

方式七:实现Spring事件 ServletRequestHandledEvent

  • 代码示例

    java
    import 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事件代码无侵入、自动触发无法统计后端业务层逻辑耗时接口的简易请求分析

MIT版权,未经许可禁止任何形式的转载