簡體   English   中英

覆蓋 Spring 啟動運行狀況端點

[英]Override Spring boot health endpoint

我有 2 個服務 A 和 B。A 在部署中位於 B 的前面,並且具有與 B 完全相同的 API,只是代理對 B 的請求並將響應從 B 返回給調用者。 B 連接了許多其他服務,其運行狀況端點顯示所有這些服務及其自身的運行狀況。

A & B 都是 spring boot 2.2.6 服務。

要求:當 A 的健康端點被調用時(與 B 的相同),它應該完全按照 B 所示返回健康。基本上將健康請求傳遞給 B 並將 B 的響應返回給調用者。

所以問題是我們如何覆蓋 A 的 Spring 管理的執行器運行狀況端點,以便它調用 B 並返回響應而不是顯示其運行狀況。 在這種情況下,標准彈簧靴健康指示器當然不起作用。

到目前為止,用@EndpointWebExtension(endpoint = HealthEndpoint.class)注釋的類似乎可以以某種方式用於覆蓋默認的健康端點行為,但是我收到以下異常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pathMappedEndpoints' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints]: Factory method 'pathMappedEndpoints' threw exception; nested exception is java.lang.IllegalStateException: Unable to map duplicate endpoint operations: [web request predicate GET to path 'health' produces: application/vnd.spring-boot.actuator.v3+json,application/vnd.spring-boot.actuator.v2+json,application/json] to healthEndpoint (applicationHealthWebEndpointExtension)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:882)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    at com.gi_de.aon360.Aon360FeApplication.main(Aon360FeApplication.java:16)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints]: Factory method 'pathMappedEndpoints' threw exception; nested exception is java.lang.IllegalStateException: Unable to map duplicate endpoint operations: [web request predicate GET to path 'health' produces: application/vnd.spring-boot.actuator.v3+json,application/vnd.spring-boot.actuator.v2+json,application/json] to healthEndpoint (applicationHealthWebEndpointExtension)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651)
    ... 19 more
Caused by: java.lang.IllegalStateException: Unable to map duplicate endpoint operations: [web request predicate GET to path 'health' produces: application/vnd.spring-boot.actuator.v3+json,application/vnd.spring-boot.actuator.v2+json,application/json] to healthEndpoint (applicationHealthWebEndpointExtension)
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.assertNoDuplicateOperations(EndpointDiscoverer.java:231)
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.convertToEndpoint(EndpointDiscoverer.java:198)
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.convertToEndpoints(EndpointDiscoverer.java:179)
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124)
    at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:116)
    at org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints.lambda$getEndpoints$1(PathMappedEndpoints.java:69)
    at java.util.LinkedHashMap$LinkedValues.forEach(LinkedHashMap.java:608)
    at org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints.getEndpoints(PathMappedEndpoints.java:68)
    at org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints.<init>(PathMappedEndpoints.java:63)
    at org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration.pathMappedEndpoints(WebEndpointAutoConfiguration.java:111)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 20 more

那么我們如何覆蓋健康端點? 任何示例、文檔鏈接等都會有所幫助。

更新/編輯:

覆蓋默認的 HealthWebExtension 似乎很棘手。 所以我找到了一個簡單的解決方法。 讓我知道您對此的看法:我只是通過使用屬性在application.properties文件中禁用了 springs 默認 healthendpoint : management.endpoint.health.enabled=false並使用@GetMapping("/manage/health")提供我自己的 restcontroller它基本上調用服務 B 並返回健康響應。

我不喜歡這個解決方案,因為首先它有點誤導屬性文件中的健康被禁用並且端點仍然工作。 其次,如果我使屬性為真,它只會覆蓋我的端點,而不會出現任何錯誤或警告。

如果 health 屬性設置為 true 而不是默認值,有沒有辦法讓 spring boot 選擇我的自定義 restcontroller?

服務A宕機了怎么辦? 您調用服務 A 並且響應不包括 A 的狀態。通過實現HealthIndicator接口有更好的方法。 就像是 :

@Component
public class ServiceBHealthIndicator implements HealthIndicator {

   
    @Override
    public Health health() {

        ResponseEntity<Map> response = null;

        try {
            response = WebClient.create( "url to B/health").get()
                    .retrieve()
                    .toEntity( Map.class ).block();
        } catch ( Exception e ) {
            log.error( "B is down", e );
        }

        Health health = Health.down().withDetail( "reason", "Service B does not respond" ).build();

        if ( Objects.nonNull( response ) && response.getStatusCode().is2xxSuccessful() ) {
            health = Health.up()
                    .withDetail( "reason", "Service B is up" )
                    .withDetails( response.getBody() )
                    .build();
        }
        return health;
    }
}

使用此解決方案,您將同時獲得:A 和 B 健康狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM