java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot统计耗时

SpringBoot中的7种耗时统计的实现方法与应用场景

作者:刘大华

在日常开发中,经常会遇到一些性能问题,这篇文章主要介绍了SpringBoot中的7种耗时统计的实现方法与应用场景,大家可以根据需要进行选择

前言

在日常开发中,经常会遇到一些性能问题。

比如用户反馈:“这个页面加载好慢啊!” 这个时候,你该怎么办?

首先就得找出到底是哪个方法、哪段代码执行时间过长。

只有找到了瓶颈,才能对症下药进行优化。所以说,方法耗时统计是性能优化中非常重要的一环。

接下来,我就给大家介绍七种实用的实现方式,从简单到复杂,总有一种适合你!

1. System.currentTimeMillis()

这是最原始但最直接的方式,适用于快速验证某段代码的执行时间。

public void doSomething() {
    long start = System.currentTimeMillis();

    // 模拟业务逻辑
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }

    long end = System.currentTimeMillis();
    System.out.println("方法执行耗时:" + (end - start) + "ms");
}

优点

缺点

适用场景

注意:该方法基于系统时间,不适用于高精度计时。推荐使用 System.nanoTime() 替代(见后文补充)。

2. 使用StopWatch工具类

Spring 提供了org.springframework.util.StopWatch类,支持分段计时和格式化输出,适合需要统计多个子任务耗时的场景。

import org.springframework.util.StopWatch;

public void processUserFlow() {
    StopWatch stopWatch = new StopWatch("用户处理流程");

    stopWatch.start("查询用户");
    // 查询逻辑...
    Thread.sleep(50);
    stopWatch.stop();

    stopWatch.start("更新缓存");
    // 缓存操作...
    Thread.sleep(80);
    stopWatch.stop();

    log.info(stopWatch.prettyPrint());
}

输出示例:

StopWatch '用户处理流程': running time = 130897800 ns
-----------------------------------------
ms     %     Task name
-----------------------------------------
 50.00  38%  查询用户
 80.00  62%  更新缓存

优点

缺点

适用场景

需要分析多个步骤耗时占比的复杂流程

3. 使用AOP切面+自定义注解(推荐)

通过面向切面编程(AOP),可以实现对指定方法的无侵入式耗时监控。

第一步:定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogCostTime {
    String value() default ""; // 方法描述
    long threshold() default 0; // 耗时阈值(ms),超过则告警
}

第二步:编写切面

@Aspect
@Component
@Slf4j
@Order(1) // 确保优先级
public class CostTimeAspect {

    @Around("@annotation(logCostTime)")
    public Object around(ProceedingJoinPoint pjp, LogCostTime logCostTime) throws Throwable {
        String methodName = pjp.getSignature().getName();
        String desc = logCostTime.value();
        long threshold = logCostTime.threshold();

        long start = System.nanoTime(); // 高精度计时
        Object result;
        try {
            result = pjp.proceed();
        } finally {
            long costNanos = System.nanoTime() - start;
            long costMillis = TimeUnit.NANOSECONDS.toMillis(costNanos);

            // 根据阈值决定日志级别
            if (threshold > 0 && costMillis > threshold) {
                log.warn("方法: {}.{}({}) 耗时超阈值: {} ms (阈值: {} ms)", 
                         pjp.getTarget().getClass().getSimpleName(), methodName, desc, costMillis, threshold);
            } else {
                log.info("方法: {}.{}({}) 耗时: {} ms", 
                         pjp.getTarget().getClass().getSimpleName(), methodName, desc, costMillis);
            }
        }
        return result;
    }
}

注意:需确保项目已启用 AOP,Spring Boot 默认支持;否则需添加 @EnableAspectJAutoProxy

第三步:使用注解

@Service
public class UserService {

    @LogCostTime(value = "根据ID查询用户", threshold = 50)
    public User getUserById(Long id) {
        try {
            Thread.sleep(100); // 模拟耗时
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return userRepository.findById(id);
    }
}

输出:

WARN  ... 方法: UserService.getUserById(根据ID查询用户) 耗时超阈值: 102 ms (阈值: 50 ms)

优点

适用场景

4. 使用Micrometer@Timed注解

Micrometer是现代Java应用的事实标准指标收集库,与Spring Boot Actuator深度集成,支持对接 Prometheus、Grafana、Datadog 等监控系统。

添加依赖

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

启用指标端点

management:
  endpoints:
    web:
      exposure:
        include: metrics, prometheus
  metrics:
    export:
      prometheus:
        enabled: true

使用@Timed注解

@Service
public class BusinessService {

    @Timed(
        value = "business.process.time",
        description = "业务处理耗时",
        percentiles = {0.5, 0.95, 0.99}
    )
    public void process() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

访问 /actuator/prometheus 可看到:

# HELP business_process_time_seconds  
# TYPE business_process_time_seconds summary
business_process_time_seconds_count{method="process",} 1.0
business_process_time_seconds_sum{method="process",} 0.201

优点

适用场景

5. 使用Java8的Instant与Duration

Java 8 引入了新的时间 API,更加安全和易用。

public void doSomething() {
    Instant start = Instant.now();

    // 业务逻辑
    try {
        Thread.sleep(150);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }

    Instant end = Instant.now();
    Duration duration = Duration.between(start, end);
    log.info("耗时:{} ms", duration.toMillis());
}

优点

缺点

适用场景

偏好 Java 8+ 新特性的项目

6. 异步方法耗时统计CompletableFuture

对于异步任务,可通过回调机制统计耗时。

public CompletableFuture<Void> asyncProcess() {
    long start = System.nanoTime();

    return CompletableFuture.runAsync(() -> {
        // 模拟异步任务
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).whenComplete((result, ex) -> {
        long cost = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
        log.info("异步任务耗时:{} ms", cost);
    });
}

优点

适用场景

7. 使用HandlerInterceptor统计 Web 请求耗时

在 Web 层通过拦截器统一记录所有 Controller 请求的处理时间。

@Component
public class RequestTimeInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        request.setAttribute("startTime", System.nanoTime());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        Long start = (Long) request.getAttribute("startTime");
        if (start != null) {
            long costNanos = System.nanoTime() - start;
            long costMillis = TimeUnit.NANOSECONDS.toMillis(costNanos);
            String uri = request.getRequestURI();
            log.info("HTTP {} {} 耗时: {} ms", request.getMethod(), uri, costMillis);
        }
    }
}

注册拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private RequestTimeInterceptor requestTimeInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestTimeInterceptor);
    }
}

输出:

HTTP GET /api/user/123 耗时: 105 ms

优点

适用场景

总结

方案侵入性适用场景是否推荐
System.currentTimeMillis()临时调试⚠️ 仅调试
StopWatch分段计时分析
AOP + 自定义注解核心方法监控✅✅✅ 强烈推荐
Micrometer @Timed生产监控集成✅✅✅ 生产首选
Instant + Duration现代化时间处理
CompletableFuture 回调异步任务
HandlerInterceptorWeb 请求全局监控✅✅

到此这篇关于SpringBoot中的7种耗时统计的实现方法与应用场景的文章就介绍到这了,更多相关SpringBoot统计耗时内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文