【问题标题】:How to make the `@Endpoint(id = "health")` working in Spring Boot 2.0?如何使`@Endpoint(id = "health")` 在 Spring Boot 2.0 中工作?
【发布时间】:2018-03-29 13:03:13
【问题描述】:

我已经尝试过在 Spring Boot 2.0.0.M5 中自定义 health Actuator 的新方法,如下所述:https://spring.io/blog/2017/08/22/introducing-actuator-endpoints-in-spring-boot-2-0:

@Endpoint(id = "health")
public class HealthEndpoint {
    @ReadOperation
    public Health health() {
        return new Health.Builder()
            .up()
            .withDetail("MyStatus", "is happy")
            .build();
    }
}

但是,当我对localhost:port/application/health 运行 HTTP GET 时,我仍然会得到标准的默认健康信息。我的代码完全被忽略了。

当我通过HealthIndicator 的实现使用自定义健康信息的“传统方式”时,它按预期工作,健康信息用给定的细节装饰:

@Component
public class MyHealthIndicator implements HealthIndicator {
    @Override
    public Health health() {
        return new Health.Builder()
            .up()
            .withDetail("MyStatus 1.1", "is happy")
            .withDetail("MyStatus 1.2", "is also happy")
            .build();
    }
}

问题:我还应该配置和/或实施什么才能使@Endpoint(id = "health") 解决方案工作?

我的意图不是创建自定义执行器myhealth,而是自定义现有的health 执行器。根据文档,我希望达到与实施 HealthIndicator 相同的结果。我的假设错了吗?


Maven 配置pom.xml 包含:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.M5</version>
    <relativePath/>
</parent>

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

Spring Boot 配置application.properties 包含:

endpoints.health.enabled=true
endpoints.autoconfig.enabled=true
endpoints.autoconfig.web.enabled=true

【问题讨论】:

  • 您是否将HealthEndpoint 配置为bean?为此,您通常会为其声明一个 @Bean 方法,或者,如果您使用组件扫描,请使用 @Component 注释它
  • @AndyWilkinson 好吧,我希望 @Endpoint-annotated 类在 Spring Boot 中被自动扫描。但是,现在我尝试在@Endpoint 之前添加@Component 并且没有区别。
  • @AndyWilkinson:Indra Basak 已经在下面的评论中回答我,我的失败是基于错误的假设。所以可能你也不能让它工作:)我编辑了我的问题,所以它应该更清楚。 Indra:“文档试图以现有的健康端点为例来解释新的端点基础设施。新的端点 ID 必须是唯一的,并且不应与现有的执行器端点相同。”

标签: java spring spring-boot spring-boot-actuator


【解决方案1】:

更新

  • 新的 Spring Actuator Endpoints 上的 documentation 不是很清晰。它试图以现有的健康端点为例来解释新的端点基础设施。

  • 新的端点 ID 必须是唯一的,并且不应与现有的执行器端点相同。如果尝试将下图示例的 ID 更改为health,则会出现以下异常:

     java.lang.IllegalStateException: Found two endpoints with the id 'health'
    
  • 上面关于用@Bean注解声明端点类的注释是正确的。

  • 自定义 health 端点在 Spring Boot 2.0 中没有改变。您仍然需要实现 HealthIndicator 才能添加自定义值。

自定义执行器端点

以下是在 Spring Boot 2.0 中创建自定义 Actuator 端点所需的更改。

型号

包含您的自定义信息的域。

@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class MyHealth {

    private Map<String, Object> details;

    @JsonAnyGetter
    public Map<String, Object> getDetails() {
        return this.details;
    }
}

我的健康端点

声明myhealth端点,

@Endpoint(id = "myhealth")
public class MyHealthEndpoint {

    @ReadOperation
    public MyHealth health() {
        Map<String, Object> details = new LinkedHashMap<>();
        details.put("MyStatus", "is happy");
        MyHealth health = new MyHealth();
        health.setDetails(details);

        return health;
    }
}

我的健康扩展

myhealth 端点的扩展,

@WebEndpointExtension(endpoint = MyHealthEndpoint.class)
public class MyHealthWebEndpointExtension {

    private final MyHealthEndpoint delegate;

    public MyHealthWebEndpointExtension(MyHealthEndpoint delegate) {
        this.delegate = delegate;
    }

    @ReadOperation
    public WebEndpointResponse<MyHealth> getHealth() {
        MyHealth health = delegate.health();
        return new WebEndpointResponse<>(health, 200);
    }
}

执行器配置

将两个新创建的执行器类公开为 bean 的配置,

@Configuration
public class ActuatorConfiguration {

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnEnabledEndpoint
    public MyHealthEndpoint myHealthEndpoint() {
        return new MyHealthEndpoint();
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnEnabledEndpoint
    @ConditionalOnBean({MyHealthEndpoint.class})
    public MyHealthWebEndpointExtension myHealthWebEndpointExtension(
            MyHealthEndpoint delegate) {
        return new MyHealthWebEndpointExtension(delegate);
    }
}

应用程序属性

更改为application.yml

endpoints:
  myhealth:
    enabled: true

启动应用程序后,您应该能够访问位于http://&lt;host&gt;:&lt;port&gt;/application/myhealth 的新执行器端点。

您应该会收到类似于如下所示的响应,

{
  "MyStatus": "is happy"
}

可以在here找到一个完整的工作示例。

【讨论】:

  • 谢谢,它 - 几乎 - 工作 :) 它以某种方式复制了信息,输出是 { "details": { "MyStatus": "is happy" }, "MyStatus": "is happy" }
【解决方案2】:

提供你自己的@WebEndpointlike

@Component
@WebEndpoint(id = "acmehealth")
public class AcmeHealthEndpoint {

    @ReadOperation
    public String hello() {
      return "hello health";
    }
}

  1. 包括它
  2. 将原始/health 映射到/internal/health
  3. 将您的自定义端点映射到/health

通过application.properties:

management.endpoints.web.exposure.include=acmehealth
management.endpoints.web.path-mapping.health=internal/health
management.endpoints.web.path-mapping.acmehealth=/health

这将完全覆盖/health,而不是像自定义HealthIndicator 那样将信息添加到现有/health。问题是,你想要什么,因为@Endpoint(id = "health") 和“我的意图不是创建自定义执行器 myhealth,而是自定义现有的健康执行器”之类的冲突。但是您可以在 AcmeHealthEndpoint 中使用现有的HealthEndpoint 并同时完成这两项工作:

@Component
@WebEndpoint(id = "prettyhealth")
public class PrettyHealthEndpoint {

    private final HealthEndpoint healthEndpoint;
    private final ObjectMapper objectMapper;

    @Autowired
    public PrettyHealthEndpoint(HealthEndpoint healthEndpoint, ObjectMapper objectMapper) {
        this.healthEndpoint = healthEndpoint;
        this.objectMapper = objectMapper;
    }

    @ReadOperation(produces = "application/json")
    public String getHealthJson() throws JsonProcessingException {
        Health health = healthEndpoint.health();
        ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter();
        return writer.writeValueAsString(health);
    }

    @ReadOperation
    public String prettyHealth() throws JsonProcessingException {
        return "<html><body><pre>" + getHealthJson() + "</pre></body></html>";
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2020-05-04
    • 2018-05-31
    • 2018-08-03
    相关资源
    最近更新 更多