知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 可觀測性

Spring Boot
HongKong
4
11:43 AM · Dec 06 ,2025

1. 概述

本教程將教你如何配置 Spring Boot 3 的可觀測性。 可觀測性是指僅通過其外部輸出(日誌、指標和跟蹤)來衡量系統內部狀態的能力。 你可以在“分佈式系統中的可觀測性”中瞭解基本概念。

此外,我們必須意識到 Spring Boot 2 (Spring 5) 和 Spring Boot 3 (Spring 6) 之間存在顯著差異。 Spring 6 引入了 Spring 可觀測性,這是一個建立在 Micrometer 和 Micrometer Tracing (以前稱為 Spring Cloud Sleuth) 之上的新舉措。 它主要用於使用 Micrometer 記錄應用程序指標以及通過提供者(如 OpenZipkin 的 Brave 或 OpenTelemetry)實現跟蹤。 Spring 可觀測性優於基於代理的可觀測性解決方案, 因為它可以在原生編譯的 Spring 應用程序中無縫工作,並提供更全面的信息。

在這裏,我們將只關注 Spring Boot 3 的細節。 如果你想從 Spring Boot 2 遷移,可以在 這裏找到詳細説明。

2. Micrometer 觀察 API

Micrometer 是一個提供 vendor-中立的應用程序指標面版的項目。它定義了 諸如儀表、速率聚合、計數器、表計和定時器等概念,每個供應商都可以根據自己的概念和工具進行調整。其中一個核心部分是 觀察 API,它允許一次性地對代碼進行指標化,並具有多項優勢。

它作為 Spring Framework 的多個部分中的依賴項包含在內,因此我們需要了解這個 API 才能理解 Spring Boot 中觀察是如何工作的。我們可以通過一個簡單的示例來完成。

2.1. 觀察 ObservationRegistry

根據 dictionary.com 的定義,“觀察”是指“對事實或事件進行觀察或記錄,通常用於科學或其他特殊目的的行為或實例”。 在我們的代碼中,我們可以觀察單個操作或完整的 HTTP 請求處理。 在這些觀察過程中,我們可以進行測量、創建用於分佈式追蹤的 span,或者僅僅記錄其他信息。

為了創建觀察,我們需要一個 ObservationRegistry:

ObservationRegistry observationRegistry = ObservationRegistry.create();
Observation observation = Observation.createNotStarted("sample", observationRegistry);

觀察具有如下生命週期,如圖所示:

我們可以使用 觀察 類型,例如:

observation.start();
try (Observation.Scope scope = observation.openScope()) {
    // ... the observed action
} catch (Exception e) {
    observation.error(e);
    // further exception handling
} finally {
    observation.stop();
}

或者簡單地説:

observation.observe(() -> {
    // ... the observed action
});

2.2. ObservationHandler

數據收集代碼被實現為一個 ObservationHandler。該處理器會收到 Observation 生命週期事件的通知,因此提供回調方法。 這樣實現一個簡單的處理器,只需打印出事件即可:

public class SimpleLoggingHandler implements ObservationHandler<Observation.Context> {

    private static final Logger log = LoggerFactory.getLogger(SimpleLoggingHandler.class);

    @Override
    public boolean supportsContext(Observation.Context context) {
        return true;
    }

    @Override
    public void onStart(Observation.Context context) {
        log.info("Starting");
    }

    @Override
    public void onScopeOpened(Observation.Context context) {
        log.info("Scope opened");
    }

    @Override
    public void onScopeClosed(Observation.Context context) {
        log.info("Scope closed");
    }

    @Override
    public void onStop(Observation.Context context) {
        log.info("Stopping");
    }

    @Override
    public void onError(Observation.Context context) {
        log.info("Error");
    }
}

我們隨後在 ObservationRegistry 中註冊 ObservationHandler,然後再創建 Observation

observationRegistry
  .observationConfig()
  .observationHandler(new SimpleLoggingHandler());

對於簡單的日誌記錄,已經存在一個實現方案。例如,為了簡單地將事件記錄到控制枱,我們可以使用:

observationRegistry
  .observationConfig()
  .observationHandler(new ObservationTextPublisher(System.out::println));

為了使用定時器樣本和計數器,我們可以配置如下:

MeterRegistry meterRegistry = new SimpleMeterRegistry();
observationRegistry
  .observationConfig()
  .observationHandler(new DefaultMeterObservationHandler(meterRegistry));

// ... observe using Observation with name "sample"

// fetch maximum duration of the named observation
Optional<Double> maximumDuration = meterRegistry.getMeters().stream()
  .filter(m -> "sample".equals(m.getId().getName()))
  .flatMap(m -> StreamSupport.stream(m.measure().spliterator(), false))
  .filter(ms -> ms.getStatistic() == Statistic.MAX)
  .findFirst()
  .map(Measurement::getValue);

3. Spring Integration

Spring Integration 是一個基於 Spring 框架的集成解決方案,它允許你構建基於消息和事件的應用程序。它提供了豐富的集成能力,包括:

  • 消息代理: 支持各種消息代理,如 RabbitMQ、Kafka、JMS 等。
  • 通道和適配器: 通過通道和適配器,將不同的系統和應用程序連接起來。
  • 流程定義: 使用 XML 或 DSL (Domain Specific Language) 定義複雜的集成流程。
  • 事件處理: 支持事件驅動的架構,允許應用程序響應外部事件。

Spring Integration 旨在簡化企業應用集成,提高開發效率和可維護性。

// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
// 這是一個簡單的 Spring Integration 示例
 recepção

3.1. Actuator

我們通過引入 Actuator 依賴,在 Spring Boot 應用中獲得最佳集成:

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

它包含一個 ObservationAutoConfiguration,它提供了一個可注入的 ObservationRegistry 實例(如果它尚不存在),並配置了 ObservationHandlers 用於收集指標和跟蹤。

例如,我們可以使用註冊表在服務中創建一個自定義的觀察結果:

@Service
public class GreetingService {

    private ObservationRegistry observationRegistry;

    // constructor

    public String sayHello() {
        return Observation
          .createNotStarted("greetingService", observationRegistry)
          .observe(this::sayHelloNoObserver);
    }

    private String sayHelloNoObserver() {
        return "Hello World!";
    }
}

此外,它還向 ObservationRegistry 註冊了 ObservationHandler Bean。我們只需要提供這些 Bean:

@Configuration
public class ObservationTextPublisherConfiguration {

    private static final Logger log = LoggerFactory.getLogger(ObservationTextPublisherConfiguration.class);

    @Bean
    public ObservationHandler<Observation.Context> observationTextPublisher() {
        return new ObservationTextPublisher(log::info);
    }
}

3.2. Web

對於 MVC,有一個過濾器 (org.springframework.web.filter.ServerHttpObservationFilter) 可以用於 HTTP 服務器觀察。當 Actuator 包含在我們的應用程序中時,此過濾器已註冊並處於活動狀態。如果未包含,則需要配置它:

@Configuration
public class ObservationFilterConfiguration {

    // if an ObservationRegistry is configured
    @ConditionalOnBean(ObservationRegistry.class)
    // if we do not use Actuator
    @ConditionalOnMissingBean(ServerHttpObservationFilter.class)
    @Bean
    public ServerHttpObservationFilter observationFilter(ObservationRegistry registry) {
        return new ServerHttpObservationFilter(registry);
    }
}

對於 WebFlux,存在一個過濾器 (org.springframework.web.filter.reactive.ServerHttpObservationFilter),但自 Spring Framework 6.1 (Spring Boot 3.2) 版本起,它已被棄用 (https://github.com/spring-projects/spring-framework/issues/31205)。相反,創建了一個 WebHttpHandlerBuilder。與 Actuator 配合使用時,這也被自動配置 (https://docs.spring.io/spring-boot/reference/web/reactive.html)。

3.3. AOP

Micrometer 觀察 API 還聲明瞭一個 @Observed 註解,其實現基於 AspectJ 的方面模型。為了使此功能正常工作,我們需要將 AOP 依賴項添加到我們的項目中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

然後,我們將該方面實現註冊為 Spring 管理的 Bean:

@Configuration
public class ObservedAspectConfiguration {

    @Bean
    public ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
        return new ObservedAspect(observationRegistry);
    }
}

現在,與其在我們的代碼中創建 Observation,不如我們儘快編寫 GreetingService

@Observed(name = "greetingService")
@Service
public class GreetingService {

    public String sayHello() {
        return "Hello World!";
    }
}

與 Actuator 結合使用時,我們可以通過 http://localhost:8080/actuator/metrics/greetingService 讀取預配置的指標(在至少調用一次服務後),並得到類似如下結果:

{
    "name": "greetingService",
    "baseUnit": "seconds",
    "measurements": [
        {
            "statistic": "COUNT",
            "value": 15
        },
        {
            "statistic": "TOTAL_TIME",
            "value": 0.0237577
        },
        {
            "statistic": "MAX",
            "value": 0.0035475
        }
    ],
    ...
}

4. 測試觀察

Micrometer 可觀測性 API 提供了一個模塊,允許我們編寫測試。 要做到這一點,我們需要添加這個依賴項:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-observation-test</artifactId>
    <scope>test</scope>
</dependency>

micrometer-bom 是 Spring Boot 管理依賴的一部分,因此我們無需指定任何版本。

由於默認情況下,整個可觀測性自動配置在測試中使用時被禁用,因此當我們想要測試默認的可觀測性時,需要使用 重新啓用它。

4.1. TestObservationRegistry</h3

我們可以使用 TestObservationRegistry,它允許使用 AssertJ 類型的斷言。因此,我們需要用 TestObservationRegistry 實例替換現有的 ObservationRegistry

例如,如果我們想要測試 GreetingService 的觀察結果,可以使用以下測試設置:

@ExtendWith(SpringExtension.class)
@ComponentScan(basePackageClasses = GreetingService.class)
@EnableAutoConfiguration
@Import(ObservedAspectConfiguration.class)
@AutoConfigureObservability
class GreetingServiceObservationIntegrationTest {

    @Autowired
    GreetingService service;
    @Autowired
    TestObservationRegistry registry;

    @TestConfiguration
    static class ObservationTestConfiguration {

        @Bean
        TestObservationRegistry observationRegistry() {
            return TestObservationRegistry.create();
        }
    }

    // ...
}

我們還可以使用 JUnit 元註解進行配置:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({
  ObservedAspectConfiguration.class,
  EnableTestObservation.ObservationTestConfiguration.class
})
@AutoConfigureObservability
public @interface EnableTestObservation {

    @TestConfiguration
    class ObservationTestConfiguration {

        @Bean
        TestObservationRegistry observationRegistry() {
            return TestObservationRegistry.create();
        }
    }
}

接下來,我們需要為我們的測試類添加註釋:

@ExtendWith(SpringExtension.class)
@ComponentScan(basePackageClasses = GreetingService.class)
@EnableAutoConfiguration
@EnableTestObservation
class GreetingServiceObservationIntegrationTest {

    @Autowired
    GreetingService service;
    @Autowired
    TestObservationRegistry registry;

    // ...
}

然後我們可以調用該服務,並檢查觀測是否已完成:

import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat;

// ...

@Test
void testObservation() {
    // invoke service
    service.sayHello();
    assertThat(registry)
      .hasObservationWithNameEqualTo("greetingService")
      .that()
      .hasBeenStarted()
      .hasBeenStopped();
}

4.2. 觀察者處理程序兼容性套件

為了測試我們的 ObservationHandler 實現,我們可以從測試中繼承的幾個基礎類(稱為 兼容性套件):

  • NullContextObservationHandlerCompatibilityKit 測試在處理 null 值參數時,觀察者處理程序是否正常工作。
  • AnyContextObservationHandlerCompatibilityKit 測試在處理未指定測試上下文參數時,觀察者處理程序是否正常工作。 這也包括 NullContextObservationHandlerCompatibilityKit
  • ConcreteContextObservationHandlerCompatibilityKit 測試在處理上下文類型的測試上下文時,觀察者處理程序是否正常工作。

實現很簡單:

public class SimpleLoggingHandlerUnitTest
  extends AnyContextObservationHandlerCompatibilityKit {

    SimpleLoggingHandler handler = new SimpleLoggingHandler();

    @Override
    public ObservationHandler<Observation.Context> handler() {
        return handler;
    }
}

這將導致以下輸出:

5. Micrometer 追蹤

前 Spring Cloud Sleuth 項目已遷移到 Micrometer,Micrometer 追蹤的核心自 Spring Boot 3 起就使用了它。 您可以在以下 文檔 中找到 Micrometer 追蹤的定義:

Micrometer 追蹤提供了一個簡單的面向對象接口,用於最流行的追蹤庫,讓您可以在不鎖定供應商的情況下,對 JVM 應用程序代碼進行儀器化。 它旨在在不增加追蹤活動開銷的情況下,最大限度地提高追蹤工作的可移植性。

我們可以獨立使用它,但它也與 Observation API 集成,通過提供 ObservationHandler 擴展。

5.1. 集成到觀察 API

為了使用 Micrometer Tracing,我們需要將以下依賴項添加到我們的項目中。版本由 Spring Boot 管理:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing</artifactId>
</dependency>

接下來,我們需要一個受支持的追蹤器(目前是 受支持的追蹤器,例如 OpenZipkin BraveOpenTelemetry)。然後,我們需要為特定供應商的集成添加 Micrometer Tracing 的依賴項:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>

Spring Actuator 具有對追蹤器的自動配置,即它會註冊供應商特定的對象和 Micrometer 追蹤的 ObservationHandler 實現,並將這些對象委託到應用程序上下文中。因此,無需進行任何進一步的配置步驟。

5.2. 測試支持

為了進行測試,我們需要將以下依賴項添加到我們的項目中。版本由 Spring Boot 管理:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-test</artifactId>
    <scope>test</scope>
</dependency>

然後我們可以使用 SimpleTracer 類在測試期間收集和驗證跟蹤數據。為了使其正常工作,我們將應用程序上下文中的原始、特定於供應商的 Tracer 替換為 SimpleTracer。 此外,我們還需要啓用跟蹤的自動配置,使用 @AutoConfigureObservability

因此,跟蹤的最小測試配置可能如下所示:

@ExtendWith(SpringExtension.class)
@EnableAutoConfiguration
@AutoConfigureObservability
public class GreetingServiceTracingIntegrationTest {

    @TestConfiguration
    static class ObservationTestConfiguration {
        @Bean
        TestObservationRegistry observationRegistry() {
            return TestObservationRegistry.create();
        }
        @Bean
        SimpleTracer simpleTracer() {
            return new SimpleTracer();
        }
    }

    @Test
    void shouldTrace() {
        // test
    }
}

或者,如果我們使用 JUnit 元註解:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@AutoConfigureObservability
@Import({
  ObservedAspectConfiguration.class,
  EnableTestObservation.ObservationTestConfiguration.class
})
public @interface EnableTestObservation {

    @TestConfiguration
    class ObservationTestConfiguration {

        @Bean
        TestObservationRegistry observationRegistry() {
            return TestObservationRegistry.create();
        }

        @Bean
        SimpleTracer simpleTracer() {
            return new SimpleTracer();
        }
    }
}

我們還可以通過以下示例測試來測試我們的 GreetingService:

import static io.micrometer.tracing.test.simple.TracerAssert.assertThat;

// ...

@Autowired
GreetingService service;
@Autowired
SimpleTracer tracer;

// ...

@Test
void testTracingForGreeting() {
    service.sayHello();
    assertThat(tracer)
      .onlySpan()
      .hasNameEqualTo("greeting-service#say-hello")
      .isEnded();
}

6. 結論

本文介紹了 Micrometer 觀察 API 以及其在 Spring Boot 3 中的集成。我們瞭解到 Micrometer 是一個與供應商無關的觀測 API,而 Micrometer Tracing 是其擴展。 此外,我們還確定了 Actuator 提供了一組預配置的觀測和跟蹤,並且默認情況下,用於測試的觀測性自動配置已禁用。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.