Spring Boot Actuator 提供的 /actuator/health 端点并不是简单的进程存活探测,它背后串联着多个健康指示器,并通过统一的聚合逻辑输出整体状态。当应用依赖数据库、消息队列、缓存或外部接口时,这些组件的连通性可以直接影响 /actuator/health 的返回结果。理解这一机制后再去扩展自定义检查,才能避免在滚动发布或故障恢复时出现误判。

一、健康端点的状态模型与聚合机制
Spring Boot Actuator 的健康体系围绕 HealthIndicator 接口展开。每个指示器只负责回答一个问题:当前组件是否健康。它的返回值是一个 Health 对象,其中至少包含一个状态值,默认状态包括 UP、DOWN、OUT_OF_SERVICE 和 UNKNOWN。这些状态不是并列关系,而是有一个内置的严重程度排序。聚合器会遍历所有已注册的指示器,如果一个指示器返回 DOWN,即使其他指示器都是 UP,最终响应的状态仍然是 DOWN。
除了状态值,Health 还能携带明细信息,例如数据库连接数、远程接口响应时间或异常类名。明细是否出现在 HTTP 响应中由 management.endpoint.health.show-details 控制,可选值为 never、always 和 when-authorized。默认值是 never,未授权时只返回状态,不会暴露组件细节。这个设计对生产环境很重要,因为健康检查响应可能被负载均衡器、容器编排平台或监控系统频繁请求,过度暴露内部信息会增加攻击面。
聚合机制还支持层级结构。一个复杂的健康检查可以是一个 CompositeHealthContributor,内部包含多个子检查。例如对某个外部系统的检查可以拆分为网络连通性、认证服务和数据同步三个子项,只要其中一项异常,整个复合检查就标记为异常。这种结构让健康状态从扁平列表变成可钻取的树,便于在排查问题时先定位故障模块。
二、内置健康指示器与常见误判场景
Actuator 在类路径下存在对应依赖时,会自动注册很多内置指示器。最常见的包括 DataSourceHealthIndicator、DiskSpaceHealthIndicator、RedisHealthIndicator、MongoHealthIndicator 和 RabbitHealthIndicator。DataSourceHealthIndicator 会向数据库执行一条验证查询,例如 SELECT 1,以此判断连接池是否可用;DiskSpaceHealthIndicator 检查工作目录的剩余空间是否低于阈值,默认阈值为 10MB。这些检查本身非常简单,但放到生产环境就可能出现意料之外的结果。
一个典型误判是数据库健康检查导致应用被频繁重启。在容器平台中,如果活性探针直接指向 /actuator/health,而数据库出现短暂波动或慢查询导致验证 SQL 超时,探针会认为应用不健康并触发重启。实际上应用进程并没有问题,重启不仅无法恢复数据库,还可能造成连接池压力进一步上升。因此通常建议将活性检查与就绪检查拆开,活性检查只关注进程本身和本地磁盘,数据库、缓存、队列等依赖放在就绪检查中。
另一个容易忽略的是磁盘空间检查。很多应用会使用临时目录存放上传文件或缓存,默认 10MB 阈值可能在生产环境过于保守,稍有波动就报告 DOWN。可以通过 management.health.diskspace.threshold 调整阈值,或者通过 management.health.diskspace.enabled=false 关闭该指示器。类似地,如果不想自动注册某个内置指示器,可以使用统一配置 management.health.defaults.enabled=false 再按需开启,保持健康端点结果可控。
三、实现自定义健康检查的两种方式
实现自定义健康检查最直接的方法是创建一个 Spring Bean,让它实现 HealthIndicator 接口。下面的示例展示了一个远程接口探活组件,它调用外部服务的 /ping 路径,根据结果返回上行或下行状态。成功时通过 withDetail 附带远程返回内容,失败时记录异常类型,方便监控系统看到问题摘要。
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
@Component
public class RemoteApiHealthIndicator implements HealthIndicator {
private final RestClient restClient;
public RemoteApiHealthIndicator(RestClient restClient) {
this.restClient = restClient;
}
@Override
public Health health() {
try {
String message = restClient.get()
.uri("/ping")
.retrieve()
.body(String.class);
return Health.up()
.withDetail("remote", "ok")
.withDetail("message", message)
.build();
} catch (Exception ex) {
return Health.down()
.withDetail("remote", "unreachable")
.withDetail("error", ex.getClass().getSimpleName())
.build();
}
}
}
如果每个检查都自己写 try-catch,代码会变得重复。Spring Boot 提供了 AbstractHealthIndicator 抽象类,它已经把异常处理封装好。继承后只需要实现 doHealthCheck 方法,在检测不通过时抛出异常,框架会自动把状态置为 DOWN 并记录异常信息。以下示例使用 JdbcTemplate 执行验证语句,如果返回结果不符合预期,直接调用 builder.down() 即可。
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class DatabaseHealthCheck extends AbstractHealthIndicator {
private final JdbcTemplate jdbcTemplate;
public DatabaseHealthCheck(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Integer result = jdbcTemplate.queryForObject("SELECT 1", Integer.class);
if (result == null || result != 1) {
builder.down().withDetail("database", "validation failed");
} else {
builder.up().withDetail("database", "normal");
}
}
}
状态的选择也值得思考。并不是所有外部依赖不可用都要返回 DOWN。例如一个非关键的下游服务偶发超时,如果直接标记为 DOWN,可能触发不必要的告警或重启。此时可以考虑返回 UNKNOWN,或者使用自定义状态。自定义状态可以通过 Health.status("WARN").withDetail("reason", "high latency").build() 实现,不过要注意聚合器只会按默认严重程度排序,自定义状态通常被视为低于 UP,具体需要结合监控平台的解析规则验证。
四、探活分组与生产环境安全
当健康检查越来越多时,把它们全部暴露在同一个 /actuator/health 端点里并不合适。Spring Boot 支持健康分组,可以创建 /actuator/health/liveness 和 /actuator/health/readiness 这样的子端点。通过配置 management.endpoint.health.group.readiness.include 指定哪些指示器属于就绪检查,哪些属于活性检查。下面是一段常见的分组配置。
management:
endpoint:
health:
show-details: when-authorized
probes:
enabled: true
health:
livenessState:
include: livenessState
readinessState:
include: readinessState
这段配置同时启用了 Kubernetes 风格的探针,并将 livenessState 和 readinessState 作为独立组暴露。在容器编排场景下,活性探针可以指向 /actuator/health/liveness,就绪探针指向 /actuator/health/readiness。这样即使数据库暂时不可用,应用也能保持存活状态,等待数据库恢复后自动就绪,而不是被反复重启。
健康检查响应中的明细可能包含内部主机名、端口、表名或错误堆栈。生产环境中应避免 show-details 设置为 always 且无任何权限控制。推荐使用 when-authorized 配合 Spring Security,只允许监控系统使用的角色访问完整明细。也可以将健康端点暴露在单独的端口上,或者由内部监控代理通过认证后采集。无论采用哪种方式,都应确保健康端点不会成为信息泄露的入口。
自定义检查还应该考虑超时和缓存。如果每个健康查询都实时访问远程接口,监控系统的轮询可能放大下游压力。可以在健康检查逻辑中增加短超时,或者在 HealthIndicator 内部做结果缓存,例如 10 秒内复用上次结果。这样既能快速响应探活请求,又能避免因下游抖动导致健康状态频繁变化。最终的目标是让健康端点反映真实的可用性,而不是成为新的不稳定来源。
Spring Boot Actuator健康检查健康监控修改时间:2026-10-01 08:09:08