SpringBoot中统计方法耗时的七种实现方式小结
目录
- 一、手动使用StopWatch
- 二、使用AOP实现全局方法耗时统计
- 三、自定义注解+AOP实现更精细的控制
- 四、使用拦截器统计Controller接口耗时
- 五、使用Actuator + Micrometer实现细粒度监控
- 六、使用Filter实现请求耗时统计
- 七、使用ServletRequestHandledEvent统计请求处理耗时
- 总结与对比
一、手动使用StopWatch
最直接的方法是使用Spring提供的StopWatch
类,这种方式简单直观,适合临时性的性能测试。
import org.springframework.util.StopWatch; @Service public class UserService { public User findUserById(Long id) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 业务逻辑 User user = userRepository.findById(id).orElse(null); stopWatch.stop(); System.out.println("findUserById方法耗时:" + stopWatch.getTotalTimeMillis() + "ms"); return user; } }
优点:简单直观,无需额外配置
缺点:侵入业务代码,不够优雅,需要手动添加到每个需要监控的方法
二、使用AOP实现全局方法耗时统计
AOP(面向切面编程)是实现方法耗时统计的理想选择,它可以在不修改原有代码的情况下,统一处理耗时统计逻辑。
首先,添加AOP依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
然后,创建切面类:
import org.ASPectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; @Aspect @Component public class MethodTimeAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void serviceMethodPointcut() {} @Around("serviceMethodPointcut()") public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable { StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 执行目标方法 Object result = joinPoint.proceed(); stopWatch.stop(); String methodName = joinPoint.getSignature().getName(); System.out.println("方法[" + methodName + "]耗时:" + stopWatch.getTotalTimeMillis() + "ms"); return result; } }
优点:代码无侵入,统一管理,配置灵活
缺点:对于特定方法的定制化需求不够灵活
三、自定义注解+AOP实现更精细的控制
这种方法结合了自定义注解和AOP,可以更精确地控制哪些方法需要进行耗时统计。
首先,创建自定义注解:
import Java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TimeLog { String value() default ""; }
然后,创建切面类处理带有该注解的方法:
import org.aspectj.lajsng.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; @Aspect @Component public class TimeLogAspect { @Around("@annotation(com.example.demo.annotation.TimeLog)") public Object timeLogAround(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signatujsre = (MethodSignature) joinPoint.getSignature(); TimeLog timeLog = signature.getMethod().getAnnotation(TimeLog.class); String methodDesc = timeLog.value().isEmpty() ? signature.getMethod().getName() : timeLog.value(); StopWatch stopWatch = new StopWatch(); stopWatch.start(); Object result = joinPoint.proceed(); stopWatch.stop(); System.out.println("方法[" + methodDesc + "]耗时:" + stopWatch.getTotalTimeMillis() + "ms"); return result; } }
使用示例:
@Service public class ProductService { @TimeLog("查询商品详情") public Product getProductDetail(Long id) { // 业务逻辑 return productRepository.findById(id).orElse(null); } }
优点:更精细的控制,注解可携带更多信息,便于定制
缺点:需要手动在方法上添加注解
四、使用拦截器统计Controller接口耗时
如果只关注Controller层的接口耗时,可以使用Spring的拦截器:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; @Component public class ApiTimeInterceptor implements HandlerInterceptor { private ThreadLocal&lpythont;Long> startTime = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, 编程客栈HttpServletResponse response, Object handler) { startTime.set(System.currentTimeMillis()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { long endTime = System.currentTimeMillis(); long executionTime = endTime - startTime.get(); String uri = request.getRequestURI(); System.out.println("接口[" + uri + "]耗时:" + executionTime + "ms"); startTime.remove(); } }
注册拦截器:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { private final ApiTimeInterceptor apiTimeInterceptor; public WebConfig(ApiTimeInterceptor apiTimeInterceptor) { this.apiTimeInterceptor = apiTimeInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(apiTimeInterceptor).addPathPatterns("/api/"); } }
优点:专注于Web接口性能,对接口进行统一监控
缺点:只能监控Controller层方法,无法监控内部服务方法
五、使用Actuator + Micrometer实现细粒度监控
Spring Boot Actuator提供了与Micrometer的集成,可以实现更专业的性能指标收集:
添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
使用Micrometer进行方法计时:
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import org.springframework.stereotype.Service; @Service public class OrderService { private final MeterRegistry meterRegistry; public OrderService(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } public Order createOrder(OrderRequest request) { Timer.Sample sample = Timer.start(meterRegistry); // 业务逻辑 Order order = processOrder(request); sample.stop(meterRegistry.timer("order.creation.time")); return order; } }
配置Actuator暴露指标:
management: endpoints: web: exposure: include: met编程客栈rics,prometheus metrics: export: prometheus: enabled: true
优点:专业的性能指标收集,可与Prometheus、Grafana等监控系统集成,适合生产环境
缺点:配置相对复杂,有一定学习成本
六、使用Filter实现请求耗时统计
创建一个Filter实现类,可以记录每次HTTP请求的开始时间和结束时间,从而计算出请求的整体耗时。
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; @Component public class TimingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long startTime = System.currentTimeMillis(); // 继续处理请求 chain.doFilter(request, response); long endTime = System.currentTimeMillis(); long executionTime = endTime - startTime; String requestUri = ((HttpServletRequest) request).getRequestURI(); System.out.println("请求[" + requestUri + "]耗时:" + executionTime + "ms"); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
优点:可以全局监控所有Web请求的耗时。
缺点:只提供整体请求的耗时,无法深入到具体业务逻辑的执行时间。
七、使用ServletRequestHandledEvent统计请求处理耗时
Spring Boot提供了ServletRequestHandledEvent
事件,可以用来监控HTTP请求的处理时间。这种方式适合于全局监控所有的请求。
首先,创建事件监听器:
import org.springframework.context.ApplicationListener; import org.springframework.web.context.request.ServletRequestHandledEvent; import org.springframework.stereotype.Component; @Component public class RequestTimingListener implements ApplicationListener<ServletRequestHandledEvent> { @Override public void onApplicationEvent(ServletRequestHandledEvent event) { System.out.println("请求[" + event.getRequestUrl() + "]耗时:" + event.getProcessingTimeMillis() + "ms"); } }
这种方法会自动监听处理结果,不需要在每个Controller中进行显式的耗时统计。
优点:不需要修改现有代码,监控全局请求的耗时
缺点:不支持自定义请求的粒度控制总结与对比
在SpringBoot中,以上七种方法各有优缺点,可以根据不同的场景选择合适的方案:
- StopWatch手动统计:适合临时测试,快速实现
- 全局AOP:适合对整个服务层进行性能监控
- 自定义注解+AOP:适合精细化控制,只监控关键方法
- 拦截器:适合Web接口监控
- Actuator+Micrometer:适合生产环境,与专业监控系统集成
- Filter:适合全局请求监控,轻量级实现
- ServletRequestHandledEvent:全局监控HTTP请求处理时间,不需改动代码
以上就是SpringBoot中统计方法耗时的七种实现方式小结的详细内容,更多关于SpringBoot统计方法耗时的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论