1. 程式人生 > 實用技巧 >SpringBoot中Actuator監控與管理

SpringBoot中Actuator監控與管理

Actuator

actuator是Spring Boot專案中非常強大的一個功能,有助於對應用程式進行監控和管理,通過Restful API請求來監管、審計、收集應用的執行情況,針對微服務而言它是必不可少的一個環節。

Endpoints

Endpoints(端點)是actuator的核心部分,它用來監視應用程式及互動,spring-boot-actuator中已經內建了非常多的Endpoints(health、info、beans、httptrace、shutdown)等等,同時也允許我們自己擴充套件自己的端點

spring boot 2.0中的端點和之前版本有較大不同,使用時需要注意。另外端點的監控機制也有很大不同,啟用了不代表可以直接訪問,還需要將其暴露出來,傳統的management.security管理已被標記為不推薦。

內建Endpoints

應用

pom配置

在pom.xml中新增spring-boot-starter-actuator的依賴

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

如果需要訪問info介面來獲取maven中的屬性內容請記得新增如下內容

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

application.yml

在application.yml檔案中配置actuator的相關配置,其中info開頭的屬性,就是訪問info端點中顯示的相關內容,值得注意的是spring boot2.x中,預設只開放了info、health兩個端點,其餘的需要自己通過配置management.endpoints.web.exposure.include屬性來載入(有include自然就有exclude)。如果想單獨操作某個端點可以使用management.endpoint.端點.enabled屬性進行啟用或者禁用。

info:
  head: head
  body: body
management:
  endpoints:
    web:
      exposure:
        # 載入所有的端點,預設只加載了info、health
        include: 
'*' endpoint: health: show-details: always # 可以關閉指定的端點 shutdown: enabled: false

測試

啟動專案,瀏覽器輸入:http://localhost:8080/actuator/info

{"head":"head","body":"body"}

自定義

上面很多都是配置相關的,以及自帶的一些端點,在實際應用中又時候預設並不能滿足我們的需求。

預設裝配HealthIndicators

下列是依賴spring-boot-xxx-starter後相關HealthIndicator的實現(通過management.health.defaults.enabled屬性可以禁用他們),但想要獲取一些額外的資訊時,自定義的作用就體現出來了。

健康端點(第一種方式)

實現HealthIndicator介面,根據自己的需要判斷返回的狀態是UP還是DOWN,功能簡單。

package com.spring.boot.health;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component("my1")
public class MyHealthIndicator implements HealthIndicator {
    private  static final String VERSION = "v1.0.0";
    @Override
    public Health health() {
        int code = 0;
        if(code != 0){
            Health.down().withDetail("code",code).withDetail("version",VERSION).build();
        }
        return Health.up().withDetail("code",code)
            .withDetail("version",VERSION).up().build();
    }
}

輸入測試地址:http://localhost:8080/actuator/health

{
    "status": "DOWN",
    "details": {
        "my1": {
            "status": "UP",
            "details": {
                "code": 0,
                "version": "v1.0.0"
            }
        },
        "rabbit": {
            "status": "DOWN",
            "details": {
                "error": "org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused (Connection refused)"
            }
        },
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 250790436864,
                "free": 67546259456,
                "threshold": 10485760
            }
        },
        "db": {
            "status": "UP",
            "details": {
                "database": "MySQL",
                "hello": 1
            }
        },
        "redis": {
            "status": "DOWN",
            "details": {
                "error": "org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.211.55.5:6379"
            }
        }
    }

可以看到當前專案的健康程度,由於沒有開啟linux虛擬機器中的redis及rabbitMQ 所以發生異常了,平時啟動專案時不去執行是不會報錯的

健康端點(第二種方式)

繼承AbstractHealthIndicator抽象類,重寫doHealthCheck方法,功能比第一種要強大一點,預設的DataSourceHealthIndicator、RedisHealthIndicator都是這種寫法,內容回撥中還做了異常的處理。

package com.spring.boot.health;

import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.stereotype.Component;

/**
 * 功能更強大,AbstractHealthIndicator實現了HealthIndicator介面
 */
@Component("my2")
public class MyAbstractHealthIndicator extends AbstractHealthIndicator {
    private static final String VERSION = "v1.0.1";
    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        int code = 0;
        if(code != 0){
            builder.down().withDetail("code",code).withDetail("version",VERSION).build();
        }
        builder.withDetail("code",code).withDetail("version",VERSION).up().build();
    }
}

測試: http://localhost:8080/actuator/health

{
    "status": "DOWN",
    "details": {
        "my2": {
            "status": "UP",
            "details": {
                "code": 0,
                "version": "v1.0.1"
            }
        },
        "my1": {
            "status": "UP",
            "details": {
                "code": 0,
                "version": "v1.0.0"
            }
        },
        "rabbit": {
            "status": "DOWN",
            "details": {
                "error": "org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused (Connection refused)"
            }
        },
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 250790436864,
                "free": 67543334912,
                "threshold": 10485760
            }
        },
        "db": {
            "status": "UP",
            "details": {
                "database": "MySQL",
                "hello": 1
            }
        },
        "redis": {
            "status": "DOWN",
            "details": {
                "error": "org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 10.211.55.5:6379"
            }
        }
    }

定義自己的端點

info、health都是spring-boot-actuator內建的,真正要實現自己的端點還得通過@Endpoint、@ReadOperator、@WriteOperation、@DeleteOperation。

不同請求的操作,呼叫時缺少必須引數,或者使用無法轉換為所需型別的引數,則不會呼叫操作方法,響應狀態為400(錯誤請求)

@Endpoint: 構建rest api的唯一路徑

@ReadOperation: GET請求,響應狀態為200 如果沒有返回值響應404(資源未找到)

@WriteOperation: POST請求,響應狀態為200如果沒有返回值響應204(無響應內容)

@DeleteOperation: DELETE請求,響應狀態為200如果沒有返回值響應204(無響應內容)

package com.spring.boot.endpoint;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;

import java.util.HashMap;
import java.util.Map;

@Endpoint(id = "jack")
public class MyEndPoint {

    @ReadOperation
    public Map<String,String> test(){
        Map<String,String> result = new HashMap<>();
        result.put("name","jack");
        result.put("age","20");
        return result;
    }

}

然後在啟動類中注入bean

package com.spring.boot;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.spring.boot.endpoint.MyEndPoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;

@EnableCaching
@SpringBootApplication
public class BootApplication{

    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class,args);
    }

    @Configuration
    static class MyEndpointConfiguration{
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnEnabledEndpoint
        public MyEndPoint myEndPoint(){
            return new MyEndPoint();
        }
    }
}

啟動專案 輸入測試地址:http://localhost:8080/actuator/jack

{"name":"jack","age":"20"}