聊聊springboot專案如何實現自定義actuator端點

語言: CN / TW / HK

前言

用過springboot的朋友,可能會知道springboot有四大神器:自動裝配、starter、cli、actuator。其中actuator可幫助你在將應用程式推送到生產環境時監控和管理應用程式。你可以選擇使用 HTTP 端點或 JMX 來管理和監控你的應用程式。 審計、健康和指標收集也可以自動應用於你的應用程式。

actuator預設為我們內建了以下端點

| ID | 描述 | 預設啟用 | 預設公開 | | -------------- | ---------------------------------------------------------- | ------------ | ------------ | | auditevents | 公開當前應用程式的審計事件資訊 | Yes | No | | beans | 顯示應用程式中所有Spring bean的完整列表 | Yes | No | | conditions | 顯示在配置和自動配置類上評估的條件以及它們是否匹配的原因 | Yes | No | | configprops | 顯示所有@ConfigurationProperties對照的列表 | Yes | No | | env | 從Spring的ConfigurableEnvironment中公開屬性 | Yes | No | | flyway | 顯示已應用的任何Flyway資料庫遷移 | Yes | No | | health | 顯示應用程式健康資訊 | Yes | Yes | | httptrace | 顯示HTTP跟蹤資訊(預設情況下,最後100個HTTP請求-響應互動) | Yes | No | | info | 顯示任意應用程式資訊 | Yes | Yes | | loggers | 顯示和修改應用程式中記錄器的配置 | Yes | No | | liquibase | 顯示已應用的任何Liquibase資料庫遷移 | Yes | No | | metrics | 顯示當前應用程式的“指標”資訊 | Yes | No | | mappings | 顯示所有@RequestMapping路徑對照的列表 | Yes | No | | scheduledtasks | 顯示應用程式中排程的任務 | Yes | No | | sessions | 允許從Spring Session支援的會話儲存中檢索和刪除使用者會話 | Yes | No | | shutdown | 讓應用程式優雅地關閉 | No | No | | threaddump | 執行執行緒轉儲 | Yes | No |

如果你的應用程式是一個web應用程式(Spring MVC、Spring WebFlux或Jersey),你可以使用以下附加端點

| ID | 描述 | 預設啟用 | 預設公開 | | ---------- | ------------------------------------------------------------ | ------------ | ------------ | | heapdump | 返回一個GZip壓縮的hprof堆轉儲檔案 | Yes | No | | jolokia | 在HTTP上公開JMX bean(當Jolokia在類路徑上時,WebFlux不可用) | Yes | No | | logfile | 返回日誌檔案的內容,支援使用HTTP Range header來檢索日誌檔案內容的一部分 | Yes | No | | prometheus | 公開指標,該格式可以被Prometheus伺服器採集 | Yes | No |

注: actuator 在springboot 1.X 和springboot 2.X 存在較大的差異,本文以springboot 2.X 作為本文的講解

通常情況下,actuator內建的端點就可以滿足我們的日常需求了,但有時候我們需要自定義端點。下面就列舉一下幾種常用的自定義端點

自定義端點

自定義前置條件,在pom.xml引入

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

1、自定義health

當內建的health端點資訊不滿足用來判斷我們專案是否健康時,我們可以自定義health

通過實現org.springframework.boot.actuate.health.HealthIndicator介面,形如

```java @Component public class CustomHealthIndicator implements HealthIndicator {

@Override
public Health health() {
    int errorCode = check();
    if (errorCode == 1) {
        return Health.down().withDetail("Error Code", errorCode).build();
    }
    return Health.up().build();
}

private int check() {
    // perform some specific health check
    return ThreadLocalRandom.current().nextInt(5);
}

} ``` 或者通過繼承org.springframework.boot.actuate.health.AbstractHealthIndicator,形如

```java @Component("otherCustom") public class CustomAbstractHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception {

    int errorCode = check();
    if (errorCode == 1) {
        builder.down().down().withDetail("Error Code", errorCode).build();
        return;
    }
    builder.up().build();

}

private int check() {
    // perform some specific health check
    return ThreadLocalRandom.current().nextInt(5);
}

}

``` 推薦使用繼承AbstractHealthIndicator 這種方式。在配置檔案中作如下配置,可以檢視詳細的健康資訊

```yml

management: endpoint: health: show-details: always ``` 通過訪問http://ip:port/actuator/health進行檢視,形如下

從圖片我們可以看出,我們自定義的health端點資訊,如果@Component不指定name,形如CustomHealthIndicator ,預設是取custom作為自定義端點物件

2、自定義info

我們可以通過實現org.springframework.boot.actuate.info.InfoContributor介面,來暴露一些我們想展示的資訊。形如

```java @Component public class CustomInfoContributor implements InfoContributor {

@Override
public void contribute(Info.Builder builder) {
    builder.withDetail("customInfo", Collections.singletonMap("hello", "world"));
}

} ``` 通過訪問http://ip:port/actuator/info進行檢視,形如下

3、自定義endpoint

有時候我們需要自定義自己的端點,我們可以通過 @Endpoint註解 + @ReadOperation、@WriteOperation、@DeleteOperation註解來實現自定義端點。形如下

```java @Component @Endpoint(id = "customEndpoint") public class CustomEndpoint {

// @ReadOperation 對應GET請求

/* * 請求示例: * GET http://localhost:8080/actuator/customEndpoint/zhangsan/20 * @param username * @param age * * @return / @ReadOperation public Map endpointByGet(@Selector String username,@Selector Integer age) { Map customMap = new HashMap<>(); customMap.put("httpMethod", HttpMethod.GET.toString()); customMap.put("username",username); customMap.put("age",age); return customMap; }

// @WriteOperation 對應POST請求

/* * 請求示例: * POST http://localhost:8080/actuator/customEndpoint * * 請求引數為json格式 * * { * "username": "zhangsan", * "age": 20 * } * * @param username 引數都為必填項 * @param age 引數都為必填項 * @return / @WriteOperation public Map endpointByPost(String username,Integer age) { Map customMap = new HashMap<>(); customMap.put("httpMethod", HttpMethod.POST.toString()); customMap.put("username",username); customMap.put("age",age); return customMap; }

// @DeleteOperation 對應Delete請求

/* * 請求示例: * DELETE http://localhost:8080/actuator/customEndpoint * * @return / @DeleteOperation public Map endpointByDelete() { Map customMap = new HashMap<>(); customMap.put("httpMethod", HttpMethod.DELETE.toString());

return customMap;

}

```

程式碼片段裡面有比較詳細的註釋,這邊就不在論述。這邊有個細節就是,我們需要在yml作如下配置來暴露我們自定義的端點

通過

```yml

management: endpoints: web: exposure: include: customEndpoint ```

或者

```yml

management: endpoints: web: exposure: include: "*"

```

總結

本文僅介紹幾種相對通用的自定義端點,更詳細的端點介紹可以檢視官網,連結如下

https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator

demo連結

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-custom-actuator-endpoint