Spring Boot Actuator 源码阅读指南:从 @Endpoint 和 @ReadOperation 开始

🔍 Spring Boot Actuator 源码阅读指南:从 @Endpoint@ReadOperation 开始

要深入理解 Spring Boot Actuator 的工作原理,最好的方式是从其核心注解入手,逐步追踪源码执行流程。本文将带你从 @Endpoint@ReadOperation 等关键注解出发,层层剖析 Actuator 的底层机制。


一、核心注解概览

Actuator 的扩展能力依赖于一组核心注解:

注解作用
@Endpoint定义一个通用端点(支持 JMX + HTTP)
@WebEndpoint仅支持 HTTP 的端点
@JmxEndpoint仅支持 JMX 的端点
@ReadOperation标记一个读取操作(GET)
@WriteOperation标记一个写入操作(POST/PUT)
@DeleteOperation标记一个删除操作(DELETE)
@Selector用于从路径中提取变量

我们以最常用的 @Endpoint + @ReadOperation 为例,展开源码分析。


二、从 @Endpoint 注解开始

1. @Endpoint 注解定义

源码位置:org.springframework.boot.actuate.endpoint.annotation.Endpoint

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Endpoint {
    String id();
    boolean enableByDefault() default true;
}
  • id():端点的唯一标识,如 healthinfo,最终映射为 /actuator/{id}
  • enableByDefault:是否默认启用

💡 示例:

@Component
@Endpoint(id = "custom")
public class CustomEndpoint { ... }

三、端点是如何被发现和注册的?

1. EndpointDiscoverer —— 端点发现器

核心类:EndpointDiscoverer<T extends AbstractEndpoint<?>>

  • 负责扫描所有带有 @Endpoint@WebEndpoint 等注解的 Bean
  • 创建对应的 Operation(读、写、删)
  • 构建 ExposableEndpoint 实例
关键方法:discoverEndpoints()
protected Collection<T> discoverEndpoints() {
    Collection<T> endpoints = new ArrayList<>();
    for (BeanDefinition candidate : getCandidateBeanDefinitions()) {
        Class<?> beanType = getBeanType(candidate);
        T endpoint = createEndpoint(beanType);
        if (endpoint != null) {
            endpoints.add(endpoint);
        }
    }
    return endpoints;
}

它会从 Spring 容器中查找所有候选 Bean,并通过反射解析注解。


2. Operation 的创建:@ReadOperation 是如何生效的?

当发现一个 @Endpoint 类时,会调用 createEndpointOperations() 解析其中的方法。

核心类:AnnotationEndpointDiscoverer

它会遍历类中的方法,查找带有 @ReadOperation@WriteOperation 等注解的方法。

private Collection<Operation> getOperations(Object endpoint, Class<?> type) {
    Collection<Operation> operations = new ArrayList<>();
    for (Method method : ReflectionUtils.getDeclaredMethods(type)) {
        if (isReadOperation(method)) {
            operations.add(createReadOperation(endpoint, method));
        } else if (isWriteOperation(method)) {
            operations.add(createWriteOperation(endpoint, method));
        }
        // ...
    }
    return operations;
}
判断是否为 @ReadOperation
private boolean isReadOperation(Method method) {
    return MergedAnnotations.from(method).isPresent(ReadOperation.class);
}

四、@ReadOperation 注解详解

1. 注解定义

源码:org.springframework.boot.actuate.endpoint.annotation.ReadOperation

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReadOperation {
}

它是一个标记注解(Marker Annotation),本身不包含属性,仅用于标识。


2. createReadOperation() 创建 WebOperation

以 Web 端点为例,最终会创建 WebOperation 实例,封装了:

  • 目标方法(Method)
  • 参数解析器(OperationParameterMapper
  • 返回值处理器
  • 路径变量(@Selector
示例:自定义端点
@Component
@Endpoint(id = "feature")
public class FeatureEndpoint {

    private Map<String, Boolean> features = new HashMap<>();

    @ReadOperation
    public Map<String, Boolean> getStatus() {
        return features;
    }

    @WriteOperation
    public void setFeature(@Selector String name, boolean enabled) {
        features.put(name, enabled);
    }
}

五、HTTP 端点是如何映射到 Web 请求的?

1. WebEndpointServletConfiguration 自动配置

spring-boot-autoconfigure 中,WebEndpointAutoConfiguration 会导入 WebEndpointServletConfiguration

它会创建:

  • WebEndpointsSupplier:提供所有可暴露的 Web 端点
  • WebEndpointDiscoverer:专门发现 @WebEndpoint@Endpoint(支持 HTTP 的)

2. WebEndpointResponseMapper 处理返回值

@ReadOperation 方法的返回值转换为 HTTP 响应体(JSON)。


3. ControllerEndpointHandlerMapping —— Spring MVC 集成

关键类:ControllerEndpointHandlerMapping

它实现了 HandlerMapping,将 /actuator/{id} 路径映射到对应的 @Endpoint 方法。

工作流程:
  1. 启动时,WebEndpointDiscoverer 扫描所有 @Endpoint Bean
  2. 构建 ExposableWebEndpoint 实例,包含 WebOperation
  3. ControllerEndpointHandlerMapping 注册这些端点为 Spring MVC 的 Handler
  4. 当请求 /actuator/feature 时,调用 FeatureEndpoint.getStatus() 方法
  5. 返回值通过 WebEndpointResponseMapper 序列化为 JSON

六、深入 @Endpoint@RestControllerEndpoint 的区别

类型注解底层机制适用场景
通用端点@Endpoint + @ReadOperation基于 OperationInvoker 反射调用推荐,轻量、跨 JMX/HTTP
Web 专用@WebEndpoint仅 HTTP,类似 @RestController简单场景
完全控制@RestControllerEndpoint完整的 @RestController 语义需要复杂逻辑、异常处理

💡 @RestControllerEndpoint 本质是一个带有 @Controller 的类,由 ControllerEndpointHandlerMapping 注册。


七、源码调用链路总结(以 /actuator/custom 为例)

1. Application Start
   └── WebEndpointDiscoverer.discoverEndpoints()
       └── 扫描 @Endpoint(id="custom") 类
       └── 解析 @ReadOperation 方法 → 创建 WebOperation

2. ControllerEndpointHandlerMapping 注册端点
   └── 将 /actuator/custom 映射到 CustomEndpoint.getStatus()

3. HTTP 请求到达
   GET /actuator/custom
   └── DispatcherServlet → HandlerMapping 匹配
   └── 调用 OperationInvoker.invoke()
   └── 反射执行 getStatus() 方法
   └── WebEndpointResponseMapper 序列化返回 JSON

八、关键源码类图(简化)

                            +---------------------+
                            |   @Endpoint         |
                            |   @ReadOperation    |
                            +----------+----------+
                                       |
                                       v
                      +----------------------------------+
                      |   EndpointDiscoverer             |
                      |   - discoverEndpoints()          |
                      |   - createOperation()            |
                      +----------------+-----------------+
                                       |
                                       v
              +------------------------+-------------------------+
              | ExposableWebEndpoint   | ExposableJmxEndpoint     |
              | - getOperations()      | - getOperations()        |
              +------------------------+-------------------------+
                                       |
                                       v
           +----------------------------------------------------------+
           | ControllerEndpointHandlerMapping                         |
           | - register endpoints as Spring MVC handlers              |
           | - handle /actuator/* requests                            |
           +----------------------------------------------------------+
                                       |
                                       v
                   +----------------------------------+
                   | OperationInvoker                 |
                   | - invoke() via reflection        |
                   +----------------------------------+

九、如何调试源码?

  1. 克隆 Spring Boot 源码

    git clone https://github.com/spring-projects/spring-boot.git
    
  2. 导入 IDE(推荐 IntelliJ IDEA)

  3. 设置断点

    • EndpointDiscoverer.discoverEndpoints()
    • AnnotationEndpointDiscoverer.getOperations()
    • ControllerEndpointHandlerMapping.getHandler()
  4. 运行你的应用,观察端点注册过程


十、总结:从注解到运行的完整理解

阶段关键动作
1. 注解定义@Endpoint, @ReadOperation 提供元数据
2. 扫描发现EndpointDiscoverer 扫描并创建端点实例
3. 操作解析解析 @ReadOperation 方法 → 创建 Operation
4. 映射注册ControllerEndpointHandlerMapping 注册为 MVC 路由
5. 请求处理反射调用方法,返回 JSON 响应

收获

  • 理解了 @Endpoint 不是简单的 Controller,而是通过元数据驱动 + 反射调用实现的通用模型。
  • 明白了为什么 @ReadOperation 方法不需要 @ResponseBody —— 因为 Actuator 内部已处理。
  • 掌握了扩展自定义端点的底层原理,便于后续定制开发。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值