源码追踪:Spring Boot Actuator HealthEndpoint 处理流程详解

🔍 源码追踪: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():获取所有 HealthIndicator
  • isShowDetails():是否显示详细信息(根据配置)

六、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();
}

✅ 结果:返回 UPDOWN 等聚合状态,并包含各组件详情。


七、6. 健康贡献者:HealthIndicator 收集

getContributors() 来源

HealthEndpoint 构造时注入:

public HealthEndpoint(Map<String, HealthContributor> contributors, 
                      HealthAggregator healthAggregator) {
    this.contributors = new UnmodifiableCompositeHealthContributor(contributors, healthAggregator);
}

这些 HealthIndicator 是如何注册的?


自动配置:HealthIndicatorAutoConfiguration

Spring Boot 为常见组件自动配置健康检查:

组件配置类HealthIndicator 实现
DataSourceDataSourceHealthIndicatorAutoConfigurationDataSourceHealthIndicator
RedisRedisHealthIndicatorAutoConfigurationRedisHealthIndicator
DiskSpace内置DiskSpaceHealthIndicator
JMSJmsHealthIndicatorAutoConfigurationJmsHealthIndicator
示例: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
  ↓
DispatcherServletControllerEndpointHandlerMapping → 匹配 HealthEndpointWebOperationInvocationHandler.invoke()HealthEndpoint.health()SimpleHealthAggregator.getHealth()
  ↓
循环调用各 HealthIndicator:DataSourceHealthIndicator.doHealthCheck()RedisHealthIndicator.doHealthCheck()DiskSpaceHealthIndicator.doHealthCheck()
  ↓
构建 Health 对象(含 status 和 details)
  ↓
Jackson 序列化为 JSONHTTP 响应返回

十一、关键源码类图

                     +---------------------+
                     |   HealthEndpoint    |
                     |   @Endpoint(id="health") |
                     +----------+----------+
                                |
                                v
            +-----------------------------------------+
            |   HealthAggregator                      |
            |   - getHealth(contributors)             |
            +-------------------+---------------------+
                                |
               +--------------+------------------+
               |                                      |
+--------------------------+       +----------------------------+
| CompositeHealthContributor |       | HealthIndicator (e.g.     |
| - db, redis, diskSpace    |       |  DataSourceHealthIndicator)|
+--------------------------+       +----------------------------+

十二、如何调试这个流程?

  1. 设置断点

    • HealthEndpoint.health()
    • SimpleHealthAggregator.getHealth()
    • DataSourceHealthIndicator.doHealthCheck()
  2. 启动应用,访问 /actuator/health

  3. 观察变量

    • contributors:包含哪些健康检查
    • includeDetails:是否显示详情
    • status:聚合后的状态

✅ 总结:HealthEndpoint 的设计精髓

特性说明
扩展性通过 HealthIndicator SPI 支持自定义健康检查
聚合性CompositeHealthContributor 支持嵌套结构
灵活性支持 show-details 动态控制
安全性可结合 Security 控制访问权限
透明性状态自动聚合,开发者无需关心顺序

📘 收获

  • 理解了 Actuator 不是简单的 Controller,而是基于 元数据 + SPI + 聚合模式 的监控框架。
  • 掌握了健康检查的数据收集、聚合、权限控制、序列化全过程。
  • 为后续自定义 HealthIndicator扩展监控逻辑打下坚实基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值