Spring Boot Actuator 是 Spring Boot 提供的一个子项目,它为应用程序添加了生产级别的监控和管理功能。通过 Actuator,开发者可以轻松地监控应用程序的运行状态、性能指标、健康状况等,而无需自己实现这些功能。
通俗理解:想象你的应用是一个病人,Actuator 就是一套完整的体检系统,可以随时检查这个"病人"的心率(请求次数)、血压(内存使用)、体温(CPU负载)等各种健康指标。
功能类别 | 具体能力 | 日常类比 |
---|---|---|
应用监控 | 查看应用基本信息、Bean信息、配置属性、环境变量等 | 查看汽车仪表盘信息 |
健康检查 | 显示应用健康状况,可集成数据库、磁盘空间等自定义健康指标 | 定期体检 |
指标收集 | 收集并展示请求次数、响应时间、JVM内存使用等指标 | 健身房的运动数据统计 |
运行时调整 | 动态修改日志级别、优雅关闭应用等 | 汽车行驶中调整空调温度 |
审计日志 | 记录用户操作事件 | 银行的交易记录 |
端点(Endpoint)是 Actuator 的核心概念,每个端点提供特定的监控或管理功能。以下是主要内置端点:
端点ID | 默认HTTP路径 | 描述 | 敏感(Sensitive) |
---|---|---|---|
health | /actuator/health | 显示应用健康状态 | 是 |
info | /actuator/info | 显示应用自定义信息 | 是 |
metrics | /actuator/metrics | 显示应用各项指标数据 | 是 |
beans | /actuator/beans | 显示所有Spring Beans及其关系 | 是 |
mappings | /actuator/mappings | 显示所有@RequestMapping路径 | 是 |
env | /actuator/env | 显示环境变量和配置属性 | 是 |
configprops | /actuator/configprops | 显示@ConfigurationProperties信息 | 是 |
loggers | /actuator/loggers | 显示和修改日志配置 | 是 |
heapdump | /actuator/heapdump | 下载堆内存快照 | 是 |
threaddump | /actuator/threaddump | 显示线程状态 | 是 |
首先需要在项目中添加 Actuator 依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
// Gradle 项目
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
在 application.properties
或 application.yml
中进行基本配置:
# 启用所有端点(默认只启用health和info)
management.endpoints.web.exposure.include=*
# 修改访问路径前缀(默认为/actuator)
management.endpoints.web.base-path=/manage
# 显示健康详情(默认只显示UP或DOWN)
management.endpoint.health.show-details=always
启动应用后,可以访问以下URL查看Actuator提供的信息:
http://localhost:8080/manage/health
- 应用健康状况http://localhost:8080/manage/info
- 应用信息http://localhost:8080/manage/metrics
- 应用指标健康端点提供应用及其依赖的健康状态。默认情况下会检查:
示例响应:
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 500105216000,
"free": 250052608000,
"threshold": 10485760
}
},
"ping": {
"status": "UP"
}
}
}
可以创建自定义健康指示器来检查特定组件的健康状态:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class CustomHealthIndicator implements HealthIndicator {
private final ExternalService externalService;
public CustomHealthIndicator(ExternalService externalService) {
this.externalService = externalService;
}
@Override
public Health health() {
// 检查外部服务是否可用
boolean isServiceUp = externalService.checkHealth();
if (!isServiceUp) {
return Health.down()
.withDetail("error", "External service is not available")
.withDetail("retryAfter", "30s")
.build();
}
return Health.up()
.withDetail("version", externalService.getVersion())
.build();
}
}
访问结果:
{
"status": "UP",
"components": {
"custom": {
"status": "UP",
"details": {
"version": "1.2.3"
}
},
// 其他健康指标...
}
}
info端点显示应用的任意信息,可以通过配置文件添加:
# application.properties
info.app.name=My Awesome App
info.app.description=A Spring Boot application for demonstration
info.app.version=1.0.0
[email protected]@
[email protected]@
访问结果:
{
"app": {
"name": "My Awesome App",
"description": "A Spring Boot application for demonstration",
"version": "1.0.0",
"encoding": "UTF-8",
"java": {
"version": "11.0.12"
}
}
}
可以通过编程方式添加更复杂的信息:
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class CustomInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
Map<String, Object> serverDetails = new HashMap<>();
serverDetails.put("availableProcessors", Runtime.getRuntime().availableProcessors());
serverDetails.put("freeMemory", Runtime.getRuntime().freeMemory());
serverDetails.put("maxMemory", Runtime.getRuntime().maxMemory());
builder.withDetail("runtime", serverDetails)
.withDetail("customMessage", "This is dynamically generated info");
}
}
访问结果:
{
"app": {
// 配置文件中定义的信息...
},
"runtime": {
"availableProcessors": 8,
"freeMemory": 123456789,
"maxMemory": 1234567890
},
"customMessage": "This is dynamically generated info"
}
Metrics端点提供了丰富的应用指标数据,包括:
查看所有可用指标:
GET /actuator/metrics
查看特定指标(如jvm.memory.used):
GET /actuator/metrics/jvm.memory.used
示例响应:
{
"name": "jvm.memory.used",
"description": "The amount of used memory",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 115343712
}
],
"availableTags": [
{
"tag": "area",
"values": ["heap", "nonheap"]
},
{
"tag": "id",
"values": ["Compressed Class Space", "PS Survivor Space", ...]
}
]
}
可以使用Micrometer注册自定义指标:
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final Counter orderCounter;
public OrderService(MeterRegistry meterRegistry) {
// 注册一个名为"orders.count"的计数器
this.orderCounter = meterRegistry.counter("orders.count");
}
public void placeOrder(Order order) {
// 业务逻辑...
// 每次下单增加计数器
orderCounter.increment();
}
}
还可以使用更复杂的指标类型:
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Timer;
@Service
public class PaymentService {
private final Timer paymentTimer;
private final DistributionSummary paymentAmountSummary;
public PaymentService(MeterRegistry meterRegistry) {
// 注册一个计时器,记录支付处理时间
this.paymentTimer = Timer.builder("payment.process.time")
.description("Time taken to process payment")
.register(meterRegistry);
// 注册一个分布摘要,记录支付金额分布
this.paymentAmountSummary = DistributionSummary.builder("payment.amount")
.description("Distribution of payment amounts")
.baseUnit("USD")
.register(meterRegistry);
}
public void processPayment(Payment payment) {
// 使用Timer.Sample记录时间
Timer.Sample sample = Timer.start();
try {
// 模拟支付处理
Thread.sleep(payment.getAmount() * 10L);
// 记录支付金额
paymentAmountSummary.record(payment.getAmount());
} finally {
// 停止计时并记录
sample.stop(paymentTimer);
}
}
}
Beans端点显示应用程序中所有Spring Beans的完整列表及其依赖关系。
访问路径:
GET /actuator/beans
示例响应:
{
"contexts": {
"application": {
"beans": {
"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.core.type.classreading.CachingMetadataReaderFactory",
"resource": "null",
"dependencies": []
},
"customHealthIndicator": {
"aliases": [],
"scope": "singleton",
"type": "com.example.demo.CustomHealthIndicator",
"resource": "file [/path/to/CustomHealthIndicator.class]",
"dependencies": ["externalService"]
},
"externalService": {
"aliases": [],
"scope": "singleton",
"type": "com.example.demo.ExternalService",
"resource": "file [/path/to/ExternalService.class]",
"dependencies": []
}
// 更多beans...
},
"parentId": null
}
}
}
Mappings端点显示所有@RequestMapping路径(包括Spring MVC和WebFlux)。
访问路径:
GET /actuator/mappings
示例响应:
{
"contexts": {
"application": {
"mappings": {
"dispatcherServlets": {
"dispatcherServlet": [
{
"handler": "public java.lang.String com.example.demo.controller.HomeController.index()",
"predicate": "{GET /}",
"details": {
"handlerMethod": {
"className": "com.example.demo.controller.HomeController",
"name": "index",
"descriptor": "()Ljava/lang/String;"
},
"requestMappingConditions": {
"consumes": [],
"headers": [],
"methods": ["GET"],
"params": [],
"patterns": ["/"],
"produces": []
}
}
},
{
"handler": "public org.springframework.http.ResponseEntity> com.example.demo.controller.HealthController.health()" ,
"predicate": "{GET /health}",
"details": {
// 类似结构...
}
}
// 更多映射...
]
}
},
"parentId": null
}
}
}
Env端点显示所有环境变量、系统属性、应用配置等。
访问路径:
GET /actuator/env
示例响应:
{
"activeProfiles": ["dev"],
"propertySources": [
{
"name": "server.ports",
"properties": {
"local.server.port": {
"value": 8080
}
}
},
{
"name": "servletContextInitParams",
"properties": {}
},
{
"name": "systemProperties",
"properties": {
"java.runtime.name": {
"value": "Java(TM) SE Runtime Environment"
},
"sun.boot.library.path": {
"value": "/path/to/jdk/lib"
}
// 更多系统属性...
}
},
{
"name": "systemEnvironment",
"properties": {
"PATH": {
"value": "/usr/bin:/bin:/usr/sbin:/sbin",
"origin": "System Environment Property \"PATH\""
},
"HOME": {
"value": "/Users/username",
"origin": "System Environment Property \"HOME\""
}
// 更多环境变量...
}
},
{
"name": "applicationConfig: [classpath:/application-dev.properties]",
"properties": {
"info.app.name": {
"value": "My Awesome App (Dev)"
},
"spring.datasource.url": {
"value": "jdbc:mysql://localhost:3306/dev_db"
}
// 更多应用配置...
}
}
]
}
Loggers端点允许查看和修改运行时日志级别。
访问路径:
GET /actuator/loggers
示例响应:
{
"levels": ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"],
"loggers": {
"ROOT": {
"configuredLevel": "INFO",
"effectiveLevel": "INFO"
},
"com": {
"configuredLevel": null,
"effectiveLevel": "INFO"
},
"com.example": {
"configuredLevel": "DEBUG",
"effectiveLevel": "DEBUG"
},
"com.example.demo": {
"configuredLevel": null,
"effectiveLevel": "DEBUG"
},
"com.example.demo.controller": {
"configuredLevel": "TRACE",
"effectiveLevel": "TRACE"
}
// 更多logger...
}
}
修改特定logger级别:
POST /actuator/loggers/com.example.demo.controller
Content-Type: application/json
{
"configuredLevel": "DEBUG"
}
响应:
204 No Content(成功)
Heapdump端点会生成一个堆内存快照(HPROF格式),用于分析内存使用情况。
访问路径:
GET /actuator/heapdump
响应:
返回一个二进制堆转储文件,可以用工具如VisualVM、Eclipse MAT等分析。
Threaddump端点提供当前所有线程的状态快照。
访问路径:
GET /actuator/threaddump
示例响应:
{
"threads": [
{
"threadName": "http-nio-8080-exec-1",
"threadId": 31,
"blockedTime": -1,
"blockedCount": 0,
"waitedTime": -1,
"waitedCount": 2,
"lockName": "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@12345678",
"lockOwnerId": -1,
"lockOwnerName": null,
"inNative": false,
"suspended": false,
"threadState": "WAITING",
"stackTrace": [
{
"methodName": "park",
"fileName": "Unsafe.java",
"lineNumber": -2,
"className": "sun.misc.Unsafe",
"nativeMethod": true
},
{
"methodName": "await",
"fileName": "AbstractQueuedSynchronizer.java",
"lineNumber": 2039,
"className": "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject",
"nativeMethod": false
}
// 更多栈帧...
],
"lockedMonitors": [],
"lockedSynchronizers": [],
"lockInfo": {
"className": "java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject",
"identityHashCode": 12345678
}
},
// 更多线程...
]
}
除了使用内置端点,还可以创建自定义端点:
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
private boolean featureEnabled = false;
@ReadOperation
public Map<String, Object> getCustomInfo() {
Map<String, Object> info = new HashMap<>();
info.put("status", featureEnabled ? "enabled" : "disabled");
info.put("timestamp", System.currentTimeMillis());
info.put("message", "This is a custom endpoint");
return info;
}
@WriteOperation
public void toggleFeature(boolean enable) {
this.featureEnabled = enable;
}
}
访问自定义端点:
GET /actuator/custom
修改状态:
POST /actuator/custom
Content-Type: application/json
true
Actuator端点可能包含敏感信息,应该进行适当的安全配置:
# 只暴露必要的端点
management.endpoints.web.exposure.include=health,info,metrics
# 启用安全,要求认证
management.endpoint.health.roles=ACTUATOR
management.endpoints.web.exposure.include=*
结合Spring Security:
// 导入必要的包
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* 配置类:ActuatorSecurityConfig
* 用于为 Spring Boot Actuator 端点配置安全访问控制。
*/
@Configuration
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 配置 HTTP 安全策略
*
* @param http HttpSecurity 对象,用于构建安全配置
* @throws Exception 如果配置过程中发生异常
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 开始请求权限配置
.authorizeRequests()
// /actuator/health 允许所有用户访问(无需认证)
.antMatchers("/actuator/health").permitAll()
// /actuator/info 允许所有用户访问(无需认证)
.antMatchers("/actuator/info").permitAll()
// 所有其他 /actuator/** 路径需要拥有 "ACTUATOR" 角色的用户才能访问
.antMatchers("/actuator/**").hasRole("ACTUATOR")
// 其他任何请求都需要身份验证
.anyRequest().authenticated()
.and()
// 启用 HTTP Basic 认证方式
.httpBasic();
}
/**
* 提供一个内存中的 UserDetailsService 实现
* 主要用于测试环境或简单场景
*
* @return UserDetailsService 实例
*/
@Bean
@Override
public UserDetailsService userDetailsService() {
// 创建一个 InMemoryUserDetailsManager,并添加一个用户
return new InMemoryUserDetailsManager(
// 构建一个用户对象
User.withDefaultPasswordEncoder()
.username("admin") // 用户名
.password("secret") // 密码(明文,使用 withDefaultPasswordEncoder 加密)
.roles("ACTUATOR") // 角色为 ACTUATOR
.build()
);
}
}
Actuator使用Micrometer作为指标门面,可以轻松集成各种监控系统:
<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-registry-prometheusartifactId>
dependency>
management.endpoints.web.exposure.include=health,info,prometheus
GET /actuator/prometheus
<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-registry-influxartifactId>
dependency>
management.metrics.export.influx.uri=http://localhost:8086
management.metrics.export.influx.db=mydb
management.metrics.export.influx.user=admin
management.metrics.export.influx.password=secret
management.metrics.export.influx.step=30s
可以过滤或转换指标数据:
import io.micrometer.core.instrument.config.MeterFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MetricsConfig {
@Bean
public MeterFilter renameTagFilter() {
return MeterFilter.renameTag("http.server.requests", "uri", "path");
}
@Bean
public MeterFilter ignorePathsFilter() {
return MeterFilter.deny(id -> {
String uri = id.getTag("uri");
return uri != null && (uri.startsWith("/actuator") || uri.equals("/favicon.ico"));
});
}
@Bean
public MeterFilter commonTagsFilter() {
return MeterFilter.commonTags(Arrays.asList(
Tag.of("region", "us-east-1"),
Tag.of("application", "my-app")
));
}
}
Actuator提供了审计事件框架:
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
@Service
public class LoginService {
private final AuditEventRepository auditEventRepository;
public LoginService(AuditEventRepository auditEventRepository) {
this.auditEventRepository = auditEventRepository;
}
public void login(String username, boolean success) {
Map<String, Object> data = new HashMap<>();
data.put("ip", "192.168.1.100");
data.put("userAgent", "Chrome/91.0");
AuditEvent event = new AuditEvent(
username,
success ? "AUTHENTICATION_SUCCESS" : "AUTHENTICATION_FAILURE",
data
);
auditEventRepository.add(event);
}
}
查询审计事件:
GET /actuator/auditevents?principal=user&after=2023-01-01T00:00:00Z
环境 | 推荐暴露的端点 | 理由 |
---|---|---|
开发环境 | health, info, metrics, beans, mappings, env, loggers | 方便开发和调试 |
测试环境 | health, info, metrics, prometheus, threaddump | 监控性能,但不暴露过多敏感信息 |
生产环境 | health, info, metrics (或特定监控系统如prometheus) | 最小权限原则,只暴露必要的监控端点 |
特殊场景 | heapdump, threaddump (临时开启) | 只在需要诊断问题时临时开启,用完立即关闭 |
采样率调整:对于高频率指标,适当调整采样率
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.distribution.percentiles.http.server.requests=0.5,0.95,0.99
management.metrics.distribution.sla.http.server.requests=100ms,500ms,1s
指标缓存:适当配置指标缓存时间
management.metrics.export.prometheus.step=30s
端点响应压缩:启用响应压缩减少网络传输
management.endpoints.web.compression.enabled=true
在Kubernetes中,可以使用Actuator的健康检查作为就绪和存活探针:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
自定义健康组:
management.endpoint.health.group.liveness.include=livenessState,customHealth
management.endpoint.health.group.readiness.include=readinessState,db,redis
问题:配置了端点但返回404
检查步骤:
spring-boot-starter-actuator
management.endpoints.web.exposure.include
/actuator/{endpoint}
常见原因:
排查方法:
/actuator/health?showDetails=always
可能原因:
解决方案:
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.distribution.percentiles=http.server.requests:0.5,0.95,0.99
使用步骤:
GET /actuator/heapdump
场景:监控电商平台关键指标
实现:
@Service
public class OrderMetrics {
private final Counter orderCounter;
private final Timer orderProcessTimer;
private final DistributionSummary orderAmountSummary;
public OrderMetrics(MeterRegistry registry) {
this.orderCounter = registry.counter("orders.count");
this.orderProcessTimer = Timer.builder("orders.process.time")
.publishPercentiles(0.5, 0.95)
.register(registry);
this.orderAmountSummary = DistributionSummary.builder("orders.amount")
.baseUnit("USD")
.register(registry);
}
public void recordOrder(Order order) {
orderCounter.increment();
orderAmountSummary.record(order.getTotalAmount());
}
public Timer.Sample startTimer() {
return Timer.start();
}
public void stopTimer(Timer.Sample sample) {
sample.stop(orderProcessTimer);
}
}
@Component
public class InventoryHealthIndicator implements HealthIndicator {
private final InventoryService inventoryService;
public InventoryHealthIndicator(InventoryService inventoryService) {
this.inventoryService = inventoryService;
}
@Override
public Health health() {
boolean isLowInventory = inventoryService.checkLowInventoryItems();
if (isLowInventory) {
return Health.status("LOW_INVENTORY")
.withDetail("message", "Some items are running low on stock")
.withDetail("criticalItems", inventoryService.getLowInventoryItems())
.build();
}
return Health.up().build();
}
}
结合Spring Cloud Sleuth和Actuator:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-sleuthartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-sleuth-zipkinartifactId>
dependency>
management.tracing.sampling.probability=1.0
spring.zipkin.base-url=http://localhost:9411
GET /actuator/httptrace
场景:生产环境临时增加日志级别排查问题
GET /actuator/loggers/com.example.demo.service
POST /actuator/loggers/com.example.demo.service
Content-Type: application/json
{
"configuredLevel": "DEBUG"
}
POST /actuator/loggers/com.example.demo.service
Content-Type: application/json
{
"configuredLevel": "INFO"
}
通过本文的全面介绍,你应该已经掌握了Spring Boot Actuator从基础到高级的所有知识。在实际项目中,根据具体需求选择合适的特性和配置,充分发挥Actuator在生产环境监控和管理中的强大功能。
千万别点赞,不然我会骄傲的(疯狂暗示)。
喜欢的点个关注,想了解更多的可以关注微信公众号 “Eric的技术杂货库” ,提供更多的干货以及资料下载保存!