
作为开发者,我们经常需要统计方法的执行时间,以便找出性能瓶颈,优化系统响应速度。今天分享在SpringBoot框架中实现方法耗时统计的几种方法。
最直接的方法是使用Spring提供的StopWatch类,这种方式简单直观,适合临时性的性能测试。
java 体验AI代码助手 代码解读复制代码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依赖:
xml 体验AI代码助手 代码解读复制代码<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>然后,创建切面类:
java 体验AI代码助手 代码解读复制代码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,可以更精确地控制哪些方法需要进行耗时统计。
首先,创建自定义注解:
java 体验AI代码助手 代码解读复制代码import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TimeLog {
String value() default "";
}然后,创建切面类处理带有该注解的方法:
ini 体验AI代码助手 代码解读复制代码import org.aspectj.lang.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 signature = (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;
}
}使用示例:
kotlin 体验AI代码助手 代码解读复制代码@Service
public class ProductService {
@TimeLog("查询商品详情")
public Product getProductDetail(Long id) {
// 业务逻辑
return productRepository.findById(id).orElse(null);
}
}优点:更精细的控制,注解可携带更多信息,便于定制 缺点:需要手动在方法上添加注解
如果只关注Controller层的接口耗时,可以使用Spring的拦截器:
typescript 体验AI代码助手 代码解读复制代码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<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();
}
}注册拦截器:
kotlin 体验AI代码助手 代码解读复制代码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层方法,无法监控内部服务方法
Spring Boot Actuator提供了与Micrometer的集成,可以实现更专业的性能指标收集:
添加依赖:
xml 体验AI代码助手 代码解读复制代码<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进行方法计时:
java 体验AI代码助手 代码解读复制代码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暴露指标:
yaml 体验AI代码助手 代码解读复制代码management:
endpoints:
web:
exposure:
include: metrics,prometheus
metrics:
export:
prometheus:
enabled: true优点:专业的性能指标收集,可与Prometheus、Grafana等监控系统集成,适合生产环境 缺点:配置相对复杂,有一定学习成本
创建一个Filter实现类,可以记录每次HTTP请求的开始时间和结束时间,从而计算出请求的整体耗时。
java 体验AI代码助手 代码解读复制代码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请求的耗时。 缺点:只提供整体请求的耗时,无法深入到具体业务逻辑的执行时间。
Spring Boot提供了ServletRequestHandledEvent事件,可以用来监控HTTP请求的处理时间。这种方式适合于全局监控所有的请求。
首先,创建事件监听器:
typescript 体验AI代码助手 代码解读复制代码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中,以上七种方法各有优缺点,可以根据不同的场景选择合适的方案:
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。