我的探险生涯手游单机版
63.16MB · 2025-11-27
在日常开发中,经常会遇到一些性能问题。
比如用户反馈:“这个页面加载好慢啊!” 这个时候,你该怎么办?
首先就得找出到底是哪个方法、哪段代码执行时间过长。
只有找到了瓶颈,才能对症下药进行优化。所以说,方法耗时统计是性能优化中非常重要的一环。
接下来,我就给大家介绍七种实用的实现方式,从简单到复杂,总有一种适合你!
这是最原始但最直接的方式,适用于快速验证某段代码的执行时间。
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");
}
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% 更新缓存
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;
}
}
@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)
@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
Instant与DurationJava 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());
}
nanoTimeCompletableFuture对于异步任务,可通过回调机制统计耗时。
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);
});
}
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 回调 | 中 | 异步任务 | |
HandlerInterceptor | 低 | Web 请求全局监控 |
希望这篇文章对你有帮助!如果你有更好的方法,欢迎在评论区分享~ 若有不对的地方也欢迎提出指正。
《工作 5 年没碰过分布式锁,是我太菜还是公司太稳?网友:太真实了!》
《90%的人不知道!Spring官方早已不推荐@Autowired?这3种注入方式你用对了吗?》
《终于找到 Axios 最优雅的封装方式了,再也不用写重复代码了》
《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》