Actuator 端点详解
一、Actuator 概述
Spring Boot Actuator 是生产级监控与管理组件,通过 端点(Endpoint) 暴露应用的运行状态、指标、配置、日志等信息,支持 HTTP 和 JMX 两种暴露方式,是微服务可观测性的基石。
1.1 快速引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>默认只暴露 health 和 info(HTTP),JMX 暴露全部端点。
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,loggers,beans
endpoint:
health:
show-details: always1.2 核心组件
| 组件 | 职责 |
|---|---|
Endpoint | 定义端点行为,返回数据 |
HealthIndicator | 提供健康检查逻辑 |
StatusAggregator | 聚合多个健康检查结果 |
EndpointFilter | 控制端点暴露(Web / JMX) |
EndpointAutoConfiguration | 自动装配所有端点 |
二、内置端点详解
2.1 应用健康与信息
/health
GET http://localhost:8080/actuator/health{
"status": "UP",
"components": {
"db": { "status": "UP", "details": { "database": "H2" } },
"redis": { "status": "UP" },
"diskSpace": { "status": "UP", "details": { "total": 499963174912, "free": 82739216384 } }
}
}默认注册 DataSourceHealthIndicator、RedisHealthIndicator、MongoHealthIndicator、ElasticsearchHealthIndicator、DiskSpaceHealthIndicator、PingHealthIndicator 等。
/info
info:
app:
name: my-service
version: 1.0.0也可实现 InfoContributor 接口动态添加:
@Component
public class BuildInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("buildTime", LocalDateTime.now());
}
}2.2 运行时指标与监控
/metrics
GET /actuator/metrics
GET /actuator/metrics/jvm.memory.used覆盖维度:jvm.memory.used、jvm.gc.pause、jvm.threads.live、system.cpu.usage、http.server.requests、jdbc.connections.active、cache.gets、logback.events 等。
/env
GET /actuator/env
GET /actuator/env/server.port敏感信息需脱敏:
management:
endpoint:
env:
keys-to-sanitize: password,secret,key,token,.*credentials.*/loggers
无需重启即可查看和修改日志级别:
GET /actuator/loggers
POST /actuator/loggers/com.example
Content-Type: application/json
{"configuredLevel": "DEBUG"}/beans / /mappings
GET /actuator/beans
GET /actuator/mappings/beans 显示所有 Bean 信息,/mappings 展示 @RequestMapping 路径。
/threaddump
GET /actuator/threaddump{
"threads": [{
"threadName": "http-nio-8080-exec-1",
"threadId": 21,
"threadState": "WAITING",
"stackTrace": [{ "methodName": "park", "fileName": "Unsafe.java" }]
}]
}/heapdump
生成 .hprof 堆转储文件,配合 MAT 分析内存泄漏。注意:触发 Full GC,生产环境谨慎使用。
GET /actuator/heapdump2.3 配置与条件
/conditions
GET /actuator/conditions{
"contexts": {
"application": {
"positiveMatches": {
"DataSourceAutoConfiguration": [{ "condition": "OnClassCondition", "message": "found DataSource" }]
},
"negativeMatches": {
"RedisAutoConfiguration": [{ "condition": "OnClassCondition", "message": "RedisTemplate not found" }]
}
}
}
}/configprops / /scheduledtasks / /caches / /quartz
GET /actuator/configprops
GET /actuator/scheduledtasks
GET /actuator/caches
DELETE /actuator/caches/users
GET /actuator/quartz
GET /actuator/quartz/jobs2.4 运行期变更
management:
endpoint:
shutdown:
enabled: truePOST /actuator/shutdown # 优雅关闭
POST /actuator/restart # 重启(需 spring-cloud-starter-context)
POST /actuator/refresh # 配置热更新2.5 集成端点
GET /actuator/flyway
GET /actuator/liquibase
GET /actuator/integrationgraph
GET /actuator/prometheus # 需引入 micrometer-registry-prometheus/httpexchanges 需配置 HttpExchangeRepository:
@Bean
public HttpExchangeRepository httpExchangeRepository() {
return new InMemoryHttpExchangeRepository();
}2.6 端点速查表
| 端点 | HTTP | JMX | 用途 | 端点 | HTTP | JMX | 用途 |
|---|---|---|---|---|---|---|---|
/health | ✅ | ✅ | 健康状态 | /info | ✅ | ✅ | 应用元信息 |
/metrics | ✅ | ✅ | 指标 | /env | ✅ | ✅ | 环境属性 |
/loggers | ✅ | ✅ | 日志级别 | /beans | ✅ | ✅ | 容器 Bean |
/mappings | ✅ | ✅ | 请求映射 | /threaddump | ✅ | ✅ | 线程快照 |
/heapdump | ✅ | ❌ | 堆转储 | /shutdown | ✅ | ✅ | 优雅关闭 |
/configprops | ✅ | ✅ | 配置绑定 | /conditions | ✅ | ✅ | 条件评估 |
/scheduledtasks | ✅ | ✅ | 定时任务 | /caches | ✅ | ✅ | 缓存管理 |
/quartz | ✅ | ✅ | Quartz | /flyway | ✅ | ✅ | 数据库迁移 |
/liquibase | ✅ | ✅ | 数据库迁移 | /httpexchanges | ✅ | ✅ | HTTP 记录 |
/integrationgraph | ✅ | ✅ | 集成流 | /prometheus | ✅ | ❌ | 指标导出 |
/refresh | ✅ | ✅ | 配置刷新 | /restart | ✅ | ❌ | 应用重启 |
共 22 个内置端点。
三、EndpointAutoConfiguration 源码分析
自动装配核心位于 org.springframework.boot.actuate.autoconfigure.endpoint 包下。
3.1 装配入口
@Configuration(proxyBeanMethods = false)
public class EndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public EndpointIdConverter endpointIdConverter() {
return new CamelCaseToHyphenLowerCamelCaseEndpointIdConverter();
}
@Bean
public EndpointFilter endpointFilter() {
return new EndpointFilter();
}
}3.2 HealthEndpointAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class)
@AutoConfigureBefore(WebEndpointAutoConfiguration.class)
public class HealthEndpointAutoConfiguration {
@Bean @ConditionalOnMissingBean @ConditionalOnEnabledHealthContributor("health")
public HealthContributorRegistry healthContributorRegistry(
Map<String, HealthContributor> healthContributors) {
return new DefaultHealthContributorRegistry(healthContributors);
}
@Bean @ConditionalOnMissingBean
public StatusAggregator healthStatusAggregator() {
return StatusAggregator.getDefault();
}
@Bean @ConditionalOnMissingBean
public HealthEndpointGroupsRegistrar healthEndpointGroupsRegistrar(
HealthEndpointGroups healthEndpointGroups) {
return new HealthEndpointGroupsRegistrar(healthEndpointGroups);
}
@Bean @ConditionalOnMissingBean
public HealthEndpoint healthEndpoint(
HealthContributorRegistry registry, HealthEndpointGroups groups) {
return new HealthEndpoint(registry, groups);
}
}3.3 @ConditionalOnAvailableEndpoint
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Conditional(OnAvailableEndpointCondition.class)
public @interface ConditionalOnAvailableEndpoint {
Class<? extends Endpoint> endpoint();
}判断逻辑:检查 management.endpoints.web.exposure.include 或 JMX 配置 → 检查 management.endpoint.<id>.enabled=true → 默认 JMX 全部暴露,Web 仅暴露 health + info。
3.4 Web 端点适配链路
WebEndpointAutoConfiguration → WebEndpointServletHandlerMapping
→ EndpointHandlerMapping(注册路由)→ OperationInvoker(调用端点方法)
→ HealthEndpoint / InfoEndpoint ...@Configuration(proxyBeanMethods = false)
public class WebEndpointAutoConfiguration {
@Bean
public WebEndpointServletHandlerMapping webEndpointServletHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes,
CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) {
String basePath = webEndpointProperties.getBasePath(); // 默认 /actuator
return new WebEndpointServletHandlerMapping(...);
}
}四、端点暴露机制
4.1 Web 暴露
management:
endpoints:
web:
base-path: /actuator
exposure:
include: health,info,metrics
exclude: env,beans
cors:
allowed-origins: https://monitor.example.com
path-mapping:
health: /health-checkinclude支持通配符*(排除 shutdown),shutdown 需单独启用
4.2 JMX 暴露
management:
endpoints:
jmx:
exposure:
include: "*"
exclude: env,shutdown
domain: org.springframework.bootJMX 默认暴露所有端点,通过 MBeanServer 访问(JConsole / VisualVM)。
4.3 底层实现原理
public interface EndpointFilter {
boolean match(EndpointId id, Exposure exposure);
}
public class DefaultEndpointFilter implements EndpointFilter {
private final Set<EndpointId> includeIds;
private final Set<EndpointId> excludeIds;
@Override
public boolean match(EndpointId id, Exposure exposure) {
if (excludeIds.contains(id)) return false;
if (includeIds.contains(EndpointId.of("*"))) return true;
return includeIds.contains(id);
}
}Web 和 JMX 各自持有 DefaultEndpointFilter 实例。
4.4 端点发现与注册
public class WebEndpointDiscoverer extends EndpointDiscoverer<WebEndpointOperation> {
@Override
protected WebEndpointOperation createOperation(
EndpointId id, InvocationContext context, Operation operation) {
return new WebOperation(id, context, operation);
}
}EndpointDiscoverer 查找 @Endpoint、@WebEndpoint、@ServletEndpoint、@JmxEndpoint 注解的 Bean,过滤后注册。
五、实战:自定义 Health 检查
5.1 自定义 DataSource
@Component
public class CustomDataSourceHealthIndicator extends AbstractHealthIndicator {
private final DataSource dataSource;
public CustomDataSourceHealthIndicator(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute("SELECT 1");
builder.up().withDetail("database", conn.getMetaData().getDatabaseProductName())
.withDetail("url", conn.getMetaData().getURL());
} catch (Exception e) {
builder.down(e).withDetail("error", e.getMessage());
}
}
}5.2 自定义 Redis
@Component
public class CustomRedisHealthIndicator extends AbstractHealthIndicator {
private final StringRedisTemplate redisTemplate;
public CustomRedisHealthIndicator(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try {
String pong = redisTemplate.getConnectionFactory().getConnection().ping();
if ("PONG".equalsIgnoreCase(pong)) {
builder.up().withDetail("ping", pong);
} else {
builder.down().withDetail("ping", pong);
}
} catch (Exception e) {
builder.down(e).withDetail("error", e.getMessage());
}
}
}5.3 三方支付 API
@Component
public class PaymentApiHealthIndicator extends AbstractHealthIndicator {
private final RestTemplate restTemplate;
private static final String PAYMENT_HEALTH_URL = "https://api.payment.example.com/health";
public PaymentApiHealthIndicator(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try {
ResponseEntity<String> response = restTemplate.getForEntity(PAYMENT_HEALTH_URL, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
builder.up().withDetail("url", PAYMENT_HEALTH_URL)
.withDetail("statusCode", response.getStatusCodeValue());
} else {
builder.down().withDetail("url", PAYMENT_HEALTH_URL)
.withDetail("statusCode", response.getStatusCodeValue());
}
} catch (Exception e) {
builder.down(e).withDetail("url", PAYMENT_HEALTH_URL).withDetail("error", e.getMessage());
}
}
}5.4 注册与聚合结果
@Configuration
public class HealthIndicatorConfig {
@Bean
public HealthIndicator externalApiHealth() {
return new ExternalApiHealthIndicator();
}
}{
"status": "DOWN",
"components": {
"customDataSource": { "status": "UP" }, "customRedis": { "status": "UP" },
"paymentApi": { "status": "DOWN", "details": { "error": "Connection timed out" } },
"db": { "status": "UP" }, "diskSpace": { "status": "UP" }
}
}六、健康状态聚合机制
6.1 StatusAggregator 原理
多个 HealthIndicator 各自返回 Health 对象,StatusAggregator 按优先级聚合成最终状态:FATAL > OUT_OF_SERVICE > DOWN > UNKNOWN > UP。
6.2 默认聚合器
public class OrderedStatusAggregator implements StatusAggregator {
private final Set<Status> statusOrder;
public OrderedStatusAggregator() {
this.statusOrder = new LinkedHashSet<>(Arrays.asList(
Status.DOWN, Status.OUT_OF_SERVICE, Status.UP, Status.UNKNOWN));
}
@Override
public Status getAggregateStatus(Collection<Status> statuses) {
for (Status candidate : statusOrder) {
if (statuses.contains(candidate)) return candidate;
}
return Status.UNKNOWN;
}
}遍历 statusOrder,返回第一个匹配的状态。DOWN 最高,UNKNOWN 最低。
6.3 自定义聚合策略
@Component
public class CustomStatusAggregator implements StatusAggregator {
private final Set<Status> statusOrder = new LinkedHashSet<>(Arrays.asList(
new Status("FATAL", "致命错误"),
Status.DOWN, Status.OUT_OF_SERVICE, Status.UNKNOWN, Status.UP));
@Override
public Status getAggregateStatus(Collection<Status> statuses) {
for (Status candidate : statusOrder) {
if (statuses.contains(candidate)) return candidate;
}
return Status.UNKNOWN;
}
}配置 HTTP 状态码映射:
management:
endpoint:
health:
status:
order: FATAL,DOWN,OUT_OF_SERVICE,UNKNOWN,UP
http-mapping:
FATAL: 503; DOWN: 503; OUT_OF_SERVICE: 503; UP: 2006.4 分组聚合
Spring Boot 2.3+ 支持健康组:
management:
endpoint:
health:
group:
liveness:
include: ping,db; show-details: always
readiness:
include: ping,db,customRedis,paymentApiGET /actuator/health/liveness
GET /actuator/health/readiness配合 Kubernetes 探针:
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080七、安全配置
7.1 Spring Security
@Configuration
public class ActuatorSecurityConfig {
@Bean
public SecurityFilterChain actuatorFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/actuator/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN"))
.httpBasic();
return http.build();
}
}7.2 敏感信息脱敏与禁用
management:
endpoint:
env:
keys-to-sanitize: password,secret,key,token,.*credentials.*
configprops:
keys-to-sanitize: password,secret,key,token,.*credentials.*
endpoints:
web:
exposure:
include: ""
server:
port: -1八、最佳实践
- 最小暴露原则:生产环境只暴露
health和info,通过独立监控系统抓取/metrics//prometheus - 敏感信息脱敏:必须配置
keys-to-sanitize保护密码和令牌 - 健康组用于 K8s:将
liveness/readiness分组与 Kubernetes 探针联动 - 动态日志级别:利用
/loggersPOST 快速定位线上问题,排查完毕后复原 - 谨慎使用 heapdump:触发 Full GC 且生成大文件,生产环境非必要不开启
- 认证保护:所有变更类端点(shutdown、loggers POST、refresh)必须认证
- 全面自定义 HealthIndicator:将数据库、缓存、消息队列、三方 API 都纳入健康检查
- 结合 Prometheus + Grafana:
/prometheus导出指标,搭建成体系的监控告警平台