最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中的7種耗時(shí)統(tǒng)計(jì)的實(shí)現(xiàn)方法與應(yīng)用場(chǎng)景

 更新時(shí)間:2025年09月26日 08:37:01   作者:劉大華  
在日常開(kāi)發(fā)中,經(jīng)常會(huì)遇到一些性能問(wèn)題,這篇文章主要介紹了SpringBoot中的7種耗時(shí)統(tǒng)計(jì)的實(shí)現(xiàn)方法與應(yīng)用場(chǎng)景,大家可以根據(jù)需要進(jìn)行選擇

前言

在日常開(kāi)發(fā)中,經(jīng)常會(huì)遇到一些性能問(wèn)題。

比如用戶反饋:“這個(gè)頁(yè)面加載好慢??!” 這個(gè)時(shí)候,你該怎么辦?

首先就得找出到底是哪個(gè)方法、哪段代碼執(zhí)行時(shí)間過(guò)長(zhǎng)。

只有找到了瓶頸,才能對(duì)癥下藥進(jìn)行優(yōu)化。所以說(shuō),方法耗時(shí)統(tǒng)計(jì)是性能優(yōu)化中非常重要的一環(huán)。

接下來(lái),我就給大家介紹七種實(shí)用的實(shí)現(xiàn)方式,從簡(jiǎn)單到復(fù)雜,總有一種適合你!

1. System.currentTimeMillis()

這是最原始但最直接的方式,適用于快速驗(yàn)證某段代碼的執(zhí)行時(shí)間。

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

    // 模擬業(yè)務(wù)邏輯
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }

    long end = System.currentTimeMillis();
    System.out.println("方法執(zhí)行耗時(shí):" + (end - start) + "ms");
}

優(yōu)點(diǎn)

  • 無(wú)需引入任何依賴
  • 簡(jiǎn)單直觀,適合臨時(shí)調(diào)試

缺點(diǎn)

  • 代碼侵入性強(qiáng)
  • 多處使用時(shí)重復(fù)代碼多
  • 精度受系統(tǒng)時(shí)鐘影響(可能受NTP調(diào)整干擾)

適用場(chǎng)景

  • 本地開(kāi)發(fā)調(diào)試
  • 快速驗(yàn)證某段邏輯耗時(shí)

注意:該方法基于系統(tǒng)時(shí)間,不適用于高精度計(jì)時(shí)。推薦使用 System.nanoTime() 替代(見(jiàn)后文補(bǔ)充)。

2. 使用StopWatch工具類

Spring 提供了org.springframework.util.StopWatch類,支持分段計(jì)時(shí)和格式化輸出,適合需要統(tǒng)計(jì)多個(gè)子任務(wù)耗時(shí)的場(chǎng)景。

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%  更新緩存

優(yōu)點(diǎn)

  • 支持多任務(wù)分段計(jì)時(shí)
  • 輸出美觀,便于分析
  • 可命名任務(wù),提升可讀性

缺點(diǎn)

  • 仍需手動(dòng)插入代碼
  • 不適用于自動(dòng)化監(jiān)控

適用場(chǎng)景

需要分析多個(gè)步驟耗時(shí)占比的復(fù)雜流程

3. 使用AOP切面+自定義注解(推薦)

通過(guò)面向切面編程(AOP),可以實(shí)現(xiàn)對(duì)指定方法的無(wú)侵入式耗時(shí)監(jiān)控。

第一步:定義注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogCostTime {
    String value() default ""; // 方法描述
    long threshold() default 0; // 耗時(shí)閾值(ms),超過(guò)則告警
}

第二步:編寫(xiě)切面

@Aspect
@Component
@Slf4j
@Order(1) // 確保優(yōu)先級(jí)
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(); // 高精度計(jì)時(shí)
        Object result;
        try {
            result = pjp.proceed();
        } finally {
            long costNanos = System.nanoTime() - start;
            long costMillis = TimeUnit.NANOSECONDS.toMillis(costNanos);

            // 根據(jù)閾值決定日志級(jí)別
            if (threshold > 0 && costMillis > threshold) {
                log.warn("方法: {}.{}({}) 耗時(shí)超閾值: {} ms (閾值: {} ms)", 
                         pjp.getTarget().getClass().getSimpleName(), methodName, desc, costMillis, threshold);
            } else {
                log.info("方法: {}.{}({}) 耗時(shí): {} ms", 
                         pjp.getTarget().getClass().getSimpleName(), methodName, desc, costMillis);
            }
        }
        return result;
    }
}

注意:需確保項(xiàng)目已啟用 AOP,Spring Boot 默認(rèn)支持;否則需添加 @EnableAspectJAutoProxy。

第三步:使用注解

@Service
public class UserService {

    @LogCostTime(value = "根據(jù)ID查詢用戶", threshold = 50)
    public User getUserById(Long id) {
        try {
            Thread.sleep(100); // 模擬耗時(shí)
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return userRepository.findById(id);
    }
}

輸出:

WARN  ... 方法: UserService.getUserById(根據(jù)ID查詢用戶) 耗時(shí)超閾值: 102 ms (閾值: 50 ms)

優(yōu)點(diǎn)

  • 低侵入:只需添加注解
  • 可復(fù)用:一處定義,多處使用
  • 可擴(kuò)展:支持閾值告警、慢查詢監(jiān)控等

適用場(chǎng)景

  • 核心服務(wù)方法
  • 遠(yuǎn)程調(diào)用(RPC/HTTP)
  • 數(shù)據(jù)庫(kù)查詢
  • 復(fù)雜計(jì)算邏輯

4. 使用Micrometer@Timed注解

Micrometer是現(xiàn)代Java應(yīng)用的事實(shí)標(biāo)準(zhǔn)指標(biāo)收集庫(kù),與Spring Boot Actuator深度集成,支持對(duì)接 Prometheus、Grafana、Datadog 等監(jiān)控系統(tǒng)。

添加依賴

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

啟用指標(biāo)端點(diǎn)

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

使用@Timed注解

@Service
public class BusinessService {

    @Timed(
        value = "business.process.time",
        description = "業(yè)務(wù)處理耗時(shí)",
        percentiles = {0.5, 0.95, 0.99}
    )
    public void process() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

訪問(wèn) /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

優(yōu)點(diǎn)

  • 標(biāo)準(zhǔn)化指標(biāo),支持多維度聚合
  • 可視化展示(Grafana)
  • 支持報(bào)警(Prometheus Alertmanager)

適用場(chǎng)景

  • 生產(chǎn)環(huán)境性能監(jiān)控
  • 微服務(wù)架構(gòu)下的統(tǒng)一指標(biāo)體系

5. 使用Java8的Instant與Duration

Java 8 引入了新的時(shí)間 API,更加安全和易用。

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

    // 業(yè)務(wù)邏輯
    try {
        Thread.sleep(150);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }

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

優(yōu)點(diǎn)

  • 使用現(xiàn)代時(shí)間 API,語(yǔ)義清晰
  • 線程安全,避免舊 Date 的坑

缺點(diǎn)

  • 仍需手動(dòng)編碼
  • 性能略低于 nanoTime

適用場(chǎng)景

偏好 Java 8+ 新特性的項(xiàng)目

6. 異步方法耗時(shí)統(tǒng)計(jì)CompletableFuture

對(duì)于異步任務(wù),可通過(guò)回調(diào)機(jī)制統(tǒng)計(jì)耗時(shí)。

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

    return CompletableFuture.runAsync(() -> {
        // 模擬異步任務(wù)
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).whenComplete((result, ex) -> {
        long cost = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
        log.info("異步任務(wù)耗時(shí):{} ms", cost);
    });
}

優(yōu)點(diǎn)

  • 適用于非阻塞場(chǎng)景
  • 可結(jié)合線程池監(jiān)控

適用場(chǎng)景

  • 異步消息處理
  • 批量任務(wù)調(diào)度

7. 使用HandlerInterceptor統(tǒng)計(jì) Web 請(qǐng)求耗時(shí)

在 Web 層通過(guò)攔截器統(tǒng)一記錄所有 Controller 請(qǐng)求的處理時(shí)間。

@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 {} {} 耗時(shí): {} ms", request.getMethod(), uri, costMillis);
        }
    }
}

注冊(cè)攔截器:

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

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

輸出:

HTTP GET /api/user/123 耗時(shí): 105 ms

優(yōu)點(diǎn)

  • 全局覆蓋所有請(qǐng)求
  • 無(wú)需修改業(yè)務(wù)代碼

適用場(chǎng)景

  • Web 應(yīng)用整體性能監(jiān)控
  • API 網(wǎng)關(guān)層耗時(shí)分析

總結(jié)

方案侵入性適用場(chǎng)景是否推薦
System.currentTimeMillis()臨時(shí)調(diào)試?? 僅調(diào)試
StopWatch分段計(jì)時(shí)分析?
AOP + 自定義注解核心方法監(jiān)控??? 強(qiáng)烈推薦
Micrometer @Timed生產(chǎn)監(jiān)控集成??? 生產(chǎn)首選
Instant + Duration現(xiàn)代化時(shí)間處理?
CompletableFuture 回調(diào)異步任務(wù)?
HandlerInterceptorWeb 請(qǐng)求全局監(jiān)控??

到此這篇關(guān)于SpringBoot中的7種耗時(shí)統(tǒng)計(jì)的實(shí)現(xiàn)方法與應(yīng)用場(chǎng)景的文章就介紹到這了,更多相關(guān)SpringBoot統(tǒng)計(jì)耗時(shí)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java 如何判斷是否是26個(gè)英文字母

    java 如何判斷是否是26個(gè)英文字母

    這篇文章主要介紹了java 如何判斷是否是26個(gè)英文字母的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • 解決java.util.RandomAccessSubList cannot be cast to java.util.ArrayList錯(cuò)誤的問(wèn)題

    解決java.util.RandomAccessSubList cannot be cas

    當(dāng)你嘗試將RandomAccessSubList強(qiáng)制轉(zhuǎn)換為ArrayList時(shí),會(huì)拋出ClassCastException異常,解決這個(gè)問(wèn)題,你可以使用List接口進(jìn)行操作,或者使用ArrayList的構(gòu)造函數(shù)創(chuàng)建新的ArrayList對(duì)象來(lái)處理子列表
    2025-11-11
  • RabbitMq報(bào)錯(cuò)reply-code=406 reply-text=PRECONDITION_FAILED解決

    RabbitMq報(bào)錯(cuò)reply-code=406 reply-text=PRECONDITION_FAILED

    這篇文章主要為大家介紹了RabbitMq報(bào)錯(cuò)reply-code=406 reply-text=PRECONDITION_FAILED分析解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Http服務(wù)與Dubbo服務(wù)相互轉(zhuǎn)換的SpringBoot代理節(jié)點(diǎn)實(shí)現(xiàn)方式

    Http服務(wù)與Dubbo服務(wù)相互轉(zhuǎn)換的SpringBoot代理節(jié)點(diǎn)實(shí)現(xiàn)方式

    文章主要討論如何在項(xiàng)目中增加一個(gè)SpringBoot節(jié)點(diǎn),作為HTTP與Dubbo服務(wù)之間的代理節(jié)點(diǎn),該節(jié)點(diǎn)通過(guò)注冊(cè)到Eureka,提供SpringCloud服務(wù),并支持Dubbo代理Bean的管理,文章提到使用io.dubbo:spring-boot-starter-dubbo依賴,但遇到消費(fèi)者配置生產(chǎn)者的問(wèn)題
    2025-10-10
  • Java中的ArrayList和contains函數(shù)和擴(kuò)容機(jī)制(源碼詳解)

    Java中的ArrayList和contains函數(shù)和擴(kuò)容機(jī)制(源碼詳解)

    這篇文章主要介紹了Java中的ArrayList和contains函數(shù)和擴(kuò)容機(jī)制,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-10-10
  • Java調(diào)用Pytorch模型實(shí)現(xiàn)圖像識(shí)別

    Java調(diào)用Pytorch模型實(shí)現(xiàn)圖像識(shí)別

    這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用Pytorch實(shí)現(xiàn)圖像識(shí)別功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下
    2023-06-06
  • Java全能工具類之Hutool的用法詳解

    Java全能工具類之Hutool的用法詳解

    Hutool是一個(gè)Java工具類庫(kù),由國(guó)內(nèi)的程序員loolly開(kāi)發(fā),目的是提供一些方便、快捷、實(shí)用的工具類和工具方法,本文就來(lái)詳細(xì)聊聊它的使用吧
    2023-03-03
  • java跳出多重循環(huán)的三種實(shí)現(xiàn)方式

    java跳出多重循環(huán)的三種實(shí)現(xiàn)方式

    文章主要介紹了Java中跳出多重循環(huán)的三種方式:使用`break`配合標(biāo)簽、在布爾表達(dá)式中添加判斷變量、以及使用`try-catch`制造異常,每種方式都有具體的代碼示例,并輸出了相應(yīng)的執(zhí)行結(jié)果
    2025-01-01
  • JVM執(zhí)行引擎的項(xiàng)目實(shí)踐

    JVM執(zhí)行引擎的項(xiàng)目實(shí)踐

    執(zhí)行引擎是Java虛擬機(jī)核心的組成部分之一,本文主要介紹了JVM執(zhí)行引擎的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • SpringBoot集成Kafka的步驟

    SpringBoot集成Kafka的步驟

    這篇文章主要介紹了SpringBoot集成Kafka的步驟,幫助大家更好的理解和使用SpringBoot,感興趣的朋友可以了解下
    2021-01-01

最新評(píng)論

贡嘎县| 平陆县| 伽师县| 临清市| 新平| 靖宇县| 历史| 柘荣县| 广州市| 和林格尔县| 咸阳市| 镇巴县| 托克托县| 岱山县| 吉木乃县| 阜城县| 怀宁县| 香港 | 余干县| 双峰县| 宾阳县| 道孚县| 洛川县| 寿阳县| 武穴市| 洛宁县| 大埔区| 桃园县| 衡东县| 长春市| 读书| 东阿县| 息烽县| 内黄县| 定州市| 南涧| 周宁县| 六枝特区| 疏勒县| 镇安县| 明水县|