🔍 源码追踪:Spring Boot Actuator HealthEndpoint 处理流程详解
本文将带你深入 Spring Boot 源码,从 HTTP 请求进入开始,逐层追踪 /actuator/health 的完整处理流程,理解它是如何收集健康指标、聚合状态并返回 JSON 响应的。
一、整体流程概览
HTTP 请求 → DispatcherServlet
↓
ControllerEndpointHandlerMapping(路由匹配)
↓
WebOperationInvocationHandler(反射调用)
↓
HealthEndpoint#health() 方法
↓
CompositeHealthContributor(聚合多个 HealthIndicator)
↓
各 HealthIndicator 实现(DB、Disk、Redis...)
↓
Health 对象构建 → JSON 序列化 → 返回响应
我们从最外层的 HTTP 请求处理 开始,逐步深入。
二、1. HTTP 请求入口:/actuator/health
当你访问:
GET http://localhost:8080/actuator/health
这个请求由 Spring MVC 的 DispatcherServlet 接收,并通过 HandlerMapping 找到对应的处理器。
三、2. 路由映射:ControllerEndpointHandlerMapping
关键类:ControllerEndpointHandlerMapping
- 它是 Spring Boot Actuator 自动配置的一部分(
WebEndpointAutoConfiguration) - 负责将
/actuator/{id}路径映射到@Endpoint注解的 Bean
源码位置:
org.springframework.boot.actuate.endpoint.web.servlet.ControllerEndpointHandlerMapping
核心逻辑:注册端点
@Override
protected void initHandlerMethods() {
for (ExposableWebEndpoint endpoint : this.endpoints) {
registerHandlerMethod(endpoint.getEndpointBean(), mappingFor(endpoint));
}
}
✅
HealthEndpoint是一个@Endpoint(id = "health")的 Bean,因此会被注册到/actuator/health。
四、3. 方法调用:WebOperationInvocationHandler
当请求匹配到 HealthEndpoint,Spring 不是直接调用其方法,而是通过 动态代理 机制。
关键类:WebOperationInvocationHandler
- 实现了
InvocationHandler - 拦截
@ReadOperation、@WriteOperation方法调用 - 负责参数解析、异常处理、返回值包装
调用链:
proxy.health() → WebOperationInvocationHandler.invoke()
→ OperationInvoker.invoke()
→ 反射调用 HealthEndpoint.health()
五、4. 核心方法:HealthEndpoint#health()
源码位置:
org.springframework.boot.actuate.health.HealthEndpoint
方法定义:
@ReadOperation
public HealthComponent health() {
return getHealthAggregator().getHealth(getContributors(), isShowDetails());
}
getHealthAggregator():获取健康聚合策略(默认SimpleHealthAggregator)getContributors():获取所有HealthIndicatorisShowDetails():是否显示详细信息(根据配置)
六、5. 健康聚合器:HealthAggregator
默认实现:SimpleHealthAggregator
源码位置:
org.springframework.boot.actuate.health.SimpleHealthAggregator
状态优先级:
private static final Map<Status, Integer> STATUS_ORDER = new LinkedHashMap<>();
static {
STATUS_ORDER.put(Status.DOWN, 0);
STATUS_ORDER.put(Status.OUT_OF_SERVICE, 1);
STATUS_ORDER.put(Status.UP, 2);
STATUS_ORDER.put(Status.UNKNOWN, 3);
}
聚合逻辑:
public Health getHealth(Map<String, HealthContributor> contributors, boolean includeDetails) {
StatusAggregate status = new StatusAggregate(this.statusComparator);
Map<String, Health> components = new LinkedHashMap<>();
for (Map.Entry<String, HealthContributor> entry : contributors.entrySet()) {
String name = entry.getKey();
HealthContributor contributor = entry.getValue();
// 递归处理 CompositeHealthContributor(如子系统)
Health health = getHealth(contributor, includeDetails);
status.add(health.getStatus());
if (includeDetails && health.getDetails().size() > 0) {
components.put(name, health);
}
}
Status aggregatedStatus = status.getAggregateStatus();
Health.Builder builder = new Health.Builder(aggregatedStatus);
if (!components.isEmpty()) {
builder.withDetails("components", components);
}
return builder.build();
}
✅ 结果:返回
UP、DOWN等聚合状态,并包含各组件详情。
七、6. 健康贡献者:HealthIndicator 收集
getContributors() 来源
HealthEndpoint 构造时注入:
public HealthEndpoint(Map<String, HealthContributor> contributors,
HealthAggregator healthAggregator) {
this.contributors = new UnmodifiableCompositeHealthContributor(contributors, healthAggregator);
}
这些 HealthIndicator 是如何注册的?
自动配置:HealthIndicatorAutoConfiguration
Spring Boot 为常见组件自动配置健康检查:
| 组件 | 配置类 | HealthIndicator 实现 |
|---|---|---|
| DataSource | DataSourceHealthIndicatorAutoConfiguration | DataSourceHealthIndicator |
| Redis | RedisHealthIndicatorAutoConfiguration | RedisHealthIndicator |
| DiskSpace | 内置 | DiskSpaceHealthIndicator |
| JMS | JmsHealthIndicatorAutoConfiguration | JmsHealthIndicator |
示例:DataSourceHealthIndicator
public class DataSourceHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Builder builder) throws Exception {
String product = this.databaseMetaData.getDatabaseProductName();
builder.up().withDetail("database", product);
String validationQuery = getValidationQuery(product);
if (StringUtils.hasText(validationQuery)) {
Statement statement = null;
try {
statement = this.connection.createStatement();
statement.execute(validationQuery);
} finally {
if (statement != null) {
statement.close();
}
}
}
}
}
✅ 它会执行一个简单的 SQL(如
SELECT 1)来验证数据库连接。
八、7. 显示控制:show-details 配置
配置项:
management:
endpoint:
health:
show-details: always # always, never, when-authorized
源码解析:
HealthEndpointGroups 负责判断是否显示详情:
public boolean isShowDetails(Authentication authentication) {
switch (this.showDetails) {
case ALWAYS:
return true;
case NEVER:
return false;
case WHEN_AUTHORIZED:
return this.authorizedDetector.isAuthorized(authentication);
}
return false;
}
AuthorizedHealthEndpointGroup使用HealthEndpointGroup判断权限- 可结合 Spring Security 控制访问
九、8. 响应序列化:JSON 输出
最终 Health 对象通过 Jackson 序列化为 JSON。
示例输出:
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": { "database": "MySQL", "hello": 1 }
},
"diskSpace": {
"status": "UP",
"details": { "total": 500000000, "free": 200000000 }
}
}
}
序列化由 Spring MVC 的 HttpMessageConverter(如 Jackson2ObjectMapper)完成。
十、完整调用链路(精简版)
GET /actuator/health
↓
DispatcherServlet
↓
ControllerEndpointHandlerMapping → 匹配 HealthEndpoint
↓
WebOperationInvocationHandler.invoke()
↓
HealthEndpoint.health()
↓
SimpleHealthAggregator.getHealth()
↓
循环调用各 HealthIndicator:
→ DataSourceHealthIndicator.doHealthCheck()
→ RedisHealthIndicator.doHealthCheck()
→ DiskSpaceHealthIndicator.doHealthCheck()
↓
构建 Health 对象(含 status 和 details)
↓
Jackson 序列化为 JSON
↓
HTTP 响应返回
十一、关键源码类图
+---------------------+
| HealthEndpoint |
| @Endpoint(id="health") |
+----------+----------+
|
v
+-----------------------------------------+
| HealthAggregator |
| - getHealth(contributors) |
+-------------------+---------------------+
|
+--------------+------------------+
| |
+--------------------------+ +----------------------------+
| CompositeHealthContributor | | HealthIndicator (e.g. |
| - db, redis, diskSpace | | DataSourceHealthIndicator)|
+--------------------------+ +----------------------------+
十二、如何调试这个流程?
-
设置断点
HealthEndpoint.health()SimpleHealthAggregator.getHealth()DataSourceHealthIndicator.doHealthCheck()
-
启动应用,访问
/actuator/health -
观察变量
contributors:包含哪些健康检查includeDetails:是否显示详情status:聚合后的状态
✅ 总结:HealthEndpoint 的设计精髓
| 特性 | 说明 |
|---|---|
| 扩展性 | 通过 HealthIndicator SPI 支持自定义健康检查 |
| 聚合性 | CompositeHealthContributor 支持嵌套结构 |
| 灵活性 | 支持 show-details 动态控制 |
| 安全性 | 可结合 Security 控制访问权限 |
| 透明性 | 状态自动聚合,开发者无需关心顺序 |
📘 收获:
- 理解了 Actuator 不是简单的 Controller,而是基于 元数据 + SPI + 聚合模式 的监控框架。
- 掌握了健康检查的数据收集、聚合、权限控制、序列化全过程。
- 为后续自定义 HealthIndicator 或扩展监控逻辑打下坚实基础。

1742

被折叠的 条评论
为什么被折叠?



