如何使 `@Endpoint(id = "health")` 在 Spring Boot 2.0 中工作?
How to make the `@Endpoint(id = "health")` working in Spring Boot 2.0?
我已经在 Spring Boot 2.0.0.M5 中尝试了自定义健康执行器的新方法,如下所述: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();
}
}
然而,当我 运行 HTTP GET 到 localhost:port/application/health
时,我仍然得到标准的默认健康信息。我的代码完全被忽略了。
当我使用 "traditional way" 通过实施 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();
}
}
问题:我还应该配置什么 and/or 实现才能使 @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 引导配置 application.properties
包含:
endpoints.health.enabled=true
endpoints.autoconfig.enabled=true
endpoints.autoconfig.web.enabled=true
更新
新 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 中创建自定义执行器端点所需的更改。
型号
包含您的自定义信息的域。
@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);
}
}
执行器配置
将两个新创建的执行器 类 公开为 beans 的配置,
@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://<host>:<port>/application/myhealth
的新执行器端点。
您应该会收到类似于下图所示的回复,
{
"MyStatus": "is happy"
}
可以找到完整的工作示例 here。
提供你自己的@WebEndpoint
赞
@Component
@WebEndpoint(id = "acmehealth")
public class AcmeHealthEndpoint {
@ReadOperation
public String hello() {
return "hello health";
}
}
和
- 包含它
- 原图/health to, say, /internal/health
- 将您的自定义端点映射到 /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")
和 "My intention is not to create a custom actuator myhealth, but to customize the existing health actuator" 有点冲突。但是您可以在您的 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>";
}
}
我已经在 Spring Boot 2.0.0.M5 中尝试了自定义健康执行器的新方法,如下所述: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();
}
}
然而,当我 运行 HTTP GET 到 localhost:port/application/health
时,我仍然得到标准的默认健康信息。我的代码完全被忽略了。
当我使用 "traditional way" 通过实施 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();
}
}
问题:我还应该配置什么 and/or 实现才能使 @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 引导配置 application.properties
包含:
endpoints.health.enabled=true
endpoints.autoconfig.enabled=true
endpoints.autoconfig.web.enabled=true
更新
新 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 中创建自定义执行器端点所需的更改。
型号
包含您的自定义信息的域。
@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);
}
}
执行器配置
将两个新创建的执行器 类 公开为 beans 的配置,
@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://<host>:<port>/application/myhealth
的新执行器端点。
您应该会收到类似于下图所示的回复,
{
"MyStatus": "is happy"
}
可以找到完整的工作示例 here。
提供你自己的@WebEndpoint
赞
@Component
@WebEndpoint(id = "acmehealth")
public class AcmeHealthEndpoint {
@ReadOperation
public String hello() {
return "hello health";
}
}
和
- 包含它
- 原图/health to, say, /internal/health
- 将您的自定义端点映射到 /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")
和 "My intention is not to create a custom actuator myhealth, but to customize the existing health actuator" 有点冲突。但是您可以在您的 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>";
}
}