项目从第一篇就提供了 /api/v1/health,它证明 Controller 能够接收请求并返回一份业务约定的 JSON。部署平台还需要回答另外两个问题:进程是否仍能自行工作,以及这个实例当前是否应该接收新流量。
Spring Boot Actuator 提供面向运维的端点和健康贡献者模型。本章保留现有业务接口,同时增加 /actuator/health、数据库结构检查以及存活和就绪探针,为后续日志、指标、容器部署与优雅停机建立运行状态边界。
1. 两类健康接口
现有业务接口由项目自己定义:
1{2"code": 0,3"message": "success",4"data": {5"status": "UP",6"service": "spring"7}8}
它适合演示业务响应格式,也可以为客户端提供应用定义的服务信息。Actuator 健康端点面向部署平台与运维系统:
1{2"status": "UP"3}
二者职责不同,不需要强行合并:
| 接口 | 主要调用方 | 契约由谁定义 | 是否聚合基础设施状态 |
|---|---|---|---|
/api/v1/health | 业务客户端、教学页面 | 当前应用 | 默认不聚合 |
/actuator/health | 负载均衡、容器平台、运维系统 | Spring Boot Actuator | 可以聚合多个贡献者 |
运维端点的结构、状态码和暴露策略应该保持稳定,业务接口则可以围绕产品契约演进。不要让容器探针依赖带身份登录、复杂业务查询或频繁变化的响应字段。
2. 添加 Actuator
在 pom.xml 中添加 Actuator Starter:
1<dependency>2<groupId>org.springframework.boot</groupId>3<artifactId>spring-boot-starter-actuator</artifactId>4</dependency>
Spring Boot 自动配置会根据依赖创建端点、健康聚合器和 Micrometer 基础设施。应用不需要手写一个新的 Actuator Controller。
默认 Web 基础路径是 /actuator。启动应用后访问:
1curl -i http://localhost:8080/actuator/health
整体状态为 UP 时通常返回 200 OK;聚合状态为 DOWN 或 OUT_OF_SERVICE 时默认映射为 503 Service Unavailable。探针应该同时判断 HTTP 状态,而不是只在响应文本中搜索 UP。
Actuator 中的端点有「是否启用」和「是否通过 Web 暴露」两层控制。端点存在于 ApplicationContext,不表示它一定能从 HTTP 访问。默认暴露范围比较保守,后面需要其他端点时再显式加入白名单。
3. 健康贡献者
/actuator/health 会聚合容器中的 HealthContributor。其中最常见的直接实现是 HealthIndicator,每个贡献者负责检查一个具体子系统。
项目已经配置 DataSource。当相应健康自动配置条件满足时,Spring Boot 会提供数据库健康贡献者,使用数据源验证数据库连接。访问详情被允许时,可以看到类似组件:
01{02"status": "UP",03"components": {04"db": {05"status": "UP"06},07"diskSpace": {08"status": "UP"09}10}11}
整体状态由各贡献者按照状态聚合规则计算。一个关键依赖为 DOWN 时,整体通常也会变为 DOWN。
健康检查应该满足三个条件:执行快速、有明确超时、不会改变业务数据。不要在每次探针请求中扫描大表、调用没有超时的远程接口,或者执行一次真实写入。
数据库连接正常也不一定表示应用需要的表已经完成迁移。可以为当前项目增加一个很轻量的结构检查,与默认连接检查表达不同含义。
4. 自定义检查
Spring Boot 4 的健康贡献者类型位于 org.springframework.boot.health.contributor。创建一个 Bean,执行能够验证 health_status 表存在的轻量查询:
01package cn.usehook.spring.health;0203import org.springframework.boot.health.contributor.Health;04import org.springframework.boot.health.contributor.HealthIndicator;05import org.springframework.dao.DataAccessException;06import org.springframework.jdbc.core.simple.JdbcClient;07import org.springframework.stereotype.Component;0809@Component10public class DatabaseSchemaHealthIndicator implements HealthIndicator {1112private final JdbcClient jdbcClient;1314public DatabaseSchemaHealthIndicator(JdbcClient jdbcClient) {15this.jdbcClient = jdbcClient;16}1718@Override19public Health health() {20try {21jdbcClient.sql("select 1 from health_status limit 1")22.query(Integer.class)23.optional();2425return Health.up()26.withDetail("table", "health_status")27.build();28} catch (DataAccessException exception) {29return Health.down(exception).build();30}31}32}
查询在表为空时也能成功完成并返回空 Optional;表不存在、连接中断或数据库拒绝查询时才进入异常分支。health() 把已知数据访问失败转换为健康状态,因为 Actuator 聚合器需要得到一个结果,而不是让请求以普通 Controller 异常结束。
Bean 名为 databaseSchemaHealthIndicator,Actuator 会把 HealthIndicator 后缀去掉,组件 ID 因而是 databaseSchema。可以单独查看该组件:
1curl http://localhost:8080/actuator/health/databaseSchema
异常详情可能包含数据库信息,不应该默认公开给匿名调用方。生产环境可以保留服务端日志和内部监控,同时限制 HTTP 响应中详情的可见范围。
5. 存活与就绪
存活状态(Liveness)回答「应用是否处于无法自行恢复、需要重启的状态」。就绪状态(Readiness)回答「应用当前是否可以接收流量」。
01应用正在启动02-> Liveness:正常03-> Readiness:拒绝流量0405应用启动完成06-> Liveness:正常07-> Readiness:接收流量0809应用内部不可恢复10-> Liveness:失败,平台可以重启实例
显式开启探针端点,并把数据库结构检查加入就绪组:
1management:2endpoint:3health:4probes:5enabled: true6group:7readiness:8include: "readinessState,databaseSchema"
对应地址为:
1curl http://localhost:8080/actuator/health/liveness2curl http://localhost:8080/actuator/health/readiness
数据库适合影响就绪状态:数据库暂时不可用时,实例可以先退出流量,等待依赖恢复。不要把数据库、缓存或外部 API 放进存活检查;如果外部依赖整体故障,平台不断重启所有正常应用实例只会造成级联问题。
就绪检查也不是数据库查询的替代品。请求开始后依赖仍可能失败,Repository 和事务代码必须继续正确处理异常。
6. 暴露边界
只暴露确实需要的 Web 端点。把前面的探针配置与暴露规则合并后,management 的完整结构如下,不要在同一 YAML 文件中重复声明两个根 management 键:
01management:02endpoints:03web:04exposure:05include: "health,info"06endpoint:07health:08show-details: when-authorized09probes:10enabled: true11group:12readiness:13include: "readinessState,databaseSchema"
include 是白名单,不建议使用 "*" 后再期待网络环境自动保证安全。Spring Security 章节已经允许匿名访问 /actuator/health/**,并要求其余 /actuator/** 端点具有 MONITOR 角色;暴露白名单决定端点是否存在,安全规则决定已存在端点由谁访问,两层不能互相替代。env、configprops、beans、conditions 等端点可能暴露配置结构和应用内部信息,即使有身份校验也只应按实际需要开放。
也可以让管理端点使用独立端口:
1management:2server:3port: 8081
独立端口只改变监听边界,本身不等于认证或网络隔离。部署平台还要明确开放哪一个端口、哪些调用方可以访问,以及防火墙和服务发现怎样路由。
验证时至少覆盖三种状态:正常启动返回 UP、数据库结构不可访问时 Readiness 失败、业务 /api/v1/health 仍保持自己的响应契约。Actuator 解决的是运行管理入口,不取代业务接口。
应用状态能够被平台读取以后,还需要在失败发生时留下可以检索和关联的事件。下一篇继续学习日志级别、参数化日志、结构化输出与请求追踪标识。