概述
Spring Boot Actuator是Spring Boot提供的生产就绪功能模块,它为Spring Boot应用程序提供了很多监控和管理功能。通过Actuator,我们可以查看应用程序的内部状态、健康状况、指标信息、配置详情等。
Actuator提供了RESTful API端点,可以轻松集成到监控系统中,是微服务架构中不可或缺的组件。本教程将详细介绍Actuator的核心功能、配置方法以及在生产环境中的最佳实践。
核心价值与用途
应用监控:实时查看应用健康状况、性能指标(如请求数量、响应时间)、资源使用情况等。
问题诊断:当应用出现问题时,可以通过暴露的端点获取线程转储、堆内存信息、日志级别等,快速定位问题。
运行状况管理:提供就绪和存活状态探针,与 Kubernetes 等容器编排平台无缝集成,用于服务发现和滚动更新。
审计与管理:查看应用配置、环境变量、Bean 定义,甚至可以动态修改日志级别。
核心概念
端点(Endpoints)
端点是Actuator提供的REST API,每个端点都提供特定的功能:
应用配置类端点:显示应用程序的配置信息
指标类端点:显示应用程序的指标信息
操作控制类端点:提供关闭应用程序等操作

暴露方式
HTTP:通过HTTP请求访问端点
JMX:通过JMX MBean访问端点
WebSocket:通过WebSocket连接访问端点
环境准备
Maven依赖
java
<dependencies>
<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 监控指标 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Micrometer (可选,用于自定义指标) -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- 安全配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
基础配置
java
server:
port: 8080
management:
endpoints:
web:
exposure:
# 暴露所有端点
include: "*"
base-path: /actuator
endpoint:
shutdown:
enabled: true
health:
show-details: when-authorized
security:
enabled: true
info:
app:
name: @project.name@
description: @project.description@
version: @project.version@
java:
version: @java.version@
内置端点
健康检查端点
java
@RestController
@RequestMapping("/actuator/health")
public class HealthController {
@Autowired
private HealthIndicatorRegistry healthIndicatorRegistry;
@GetMapping
public Health health() {
Health.Builder builder = Health.up();
// 检查数据库连接
try {
// 数据库连接检查逻辑
builder.withDetail("database", "连接正常");
} catch (Exception e) {
builder.down().withDetail("database", e.getMessage());
}
// 检查外部服务
try {
// 外部服务检查逻辑
builder.withDetail("external-service", "服务正常");
} catch (Exception e) {
builder.status("WARN").withDetail("external-service", e.getMessage());
}
return builder.build();
}
}
// 自定义健康指示器
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 执行健康检查逻辑
boolean healthy = checkHealth();
if (healthy) {
return Health.up()
.withDetail("status", "Custom service is running")
.build();
} else {
return Health.down()
.withDetail("error", "Custom service is down")
.build();
}
}
private boolean checkHealth() {
// 自定义健康检查逻辑
return true;
}
}
// 数据库健康指示器
@Configuration
public class DatabaseHealthConfig {
@Bean
public DataSourceHealthIndicator dataSourceHealthIndicator(DataSource dataSource) {
return new DataSourceHealthIndicator(dataSource, "SELECT 1");
}
}
应用信息端点
java
@Configuration
public class InfoConfig {
@Bean
public InfoContributor customInfoContributor() {
return builder -> {
Map<String, Object> details = new HashMap<>();
details.put("build", Map.of(
"artifact", "my-app",
"name", "My Application",
"time", new Date().toString(),
"version", "1.0.0",
"group", "com.example"
));
details.put("system", Map.of(
"java.version", System.getProperty("java.version"),
"os.name", System.getProperty("os.name"),
"os.arch", System.getProperty("os.arch"),
"processors", Runtime.getRuntime().availableProcessors()
));
builder.withDetails(details);
};
}
}
// Git信息贡献者
@Configuration
public class GitInfoConfig {
@Bean
public GitInfoContributor gitInfoContributor() {
return new GitInfoContributor();
}
}
// 环境信息贡献者
@Configuration
public class EnvironmentInfoConfig {
@Autowired
private Environment environment;
@Bean
public InfoContributor environmentInfoContributor() {
return builder -> {
Map<String, Object> envDetails = new HashMap<>();
envDetails.put("activeProfiles", Arrays.toString(environment.getActiveProfiles()));
envDetails.put("defaultProfiles", Arrays.toString(environment.getDefaultProfiles()));
builder.withDetail("environment", envDetails);
};
}
}
指标端点
java
@Service
public class MetricsService {
@Autowired
private MeterRegistry meterRegistry;
// 计数器
private final Counter requestCounter = Counter.builder("http_requests_total")
.description("Total number of HTTP requests")
.tags("method", "GET")
.register(meterRegistry);
// 计时器
private final Timer requestTimer = Timer.builder("http_request_duration")
.description("HTTP request duration")
.tags("method", "GET")
.register(meterRegistry);
// 仪表
private final Gauge activeUsers = Gauge.builder("active_users", this, MetricsService::getActiveUsers)
.description("Number of active users")
.register(meterRegistry);
public void recordRequest() {
requestCounter.increment();
}
public void recordRequestDuration(long duration) {
requestTimer.record(Duration.ofMillis(duration));
}
private double getActiveUsers() {
// 获取活跃用户数的逻辑
return 42.0;
}
}
// HTTP请求指标
@Configuration
public class HttpMetricsConfig {
@Bean
public TimedAspect timedAspect(MeterRegistry meterRegistry) {
return new TimedAspect(meterRegistry);
}
}
@RestController
public class SampleController {
@Autowired
private MetricsService metricsService;
@GetMapping("/api/data")
@Timed(value = "api.data.requests", description = "Time taken to process data requests")
public String getData() {
long startTime = System.currentTimeMillis();
// 记录请求
metricsService.recordRequest();
try {
// 模拟处理时间
Thread.sleep(100);
return "Data response";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "Error";
} finally {
// 记录请求持续时间
long duration = System.currentTimeMillis() - startTime;
metricsService.recordRequestDuration(duration);
}
}
}
配置属性端点
java
@Configuration
public class ConfigPropsConfig {
@Bean
public ConfigPropsEndpoint configPropsEndpoint(Collection<ConfigurationPropertiesBean> configPropsBeans) {
return new ConfigPropsEndpoint(configPropsBeans);
}
}
// 自定义配置属性
@ConfigurationProperties(prefix = "app.custom")
public class CustomProperties {
private String name;
private int value;
private List<String> items;
// getters and setters
}
// 端点过滤器
@Configuration
public class EndpointFilterConfig {
@Bean
public EndpointFilter<ConfigPropsEndpoint> configPropsFilter() {
return new EndpointFilter<ConfigPropsEndpoint>() {
@Override
public ConfigPropsEndpoint filter(ConfigPropsEndpoint endpoint) {
// 过滤敏感配置信息
return endpoint;
}
};
}
}
日志端点
java
@Configuration
public class LoggingConfig {
@Bean
public LoggingEndpoint loggingEndpoint() {
return new LoggingEndpoint();
}
}
// 动态日志级别配置
@RestController
@RequestMapping("/actuator/logging")
public class LoggingController {
@Autowired
private LoggingSystem loggingSystem;
@PostMapping("/level")
public void setLogLevel(@RequestParam String logger, @RequestParam String level) {
loggingSystem.setLogLevel(logger, LogLevel.valueOf(level.toUpperCase()));
}
@GetMapping("/level")
public Map<String, Object> getLogLevel(@RequestParam String logger) {
Map<String, Object> result = new HashMap<>();
result.put("logger", logger);
result.put("level", loggingSystem.getLoggerConfiguration(logger));
return result;
}
}
自定义端点
基础自定义端点
java
@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> custom() {
Map<String, Object> result = new HashMap<>();
result.put("message", "Custom endpoint response");
result.put("timestamp", System.currentTimeMillis());
return result;
}
@ReadOperation
public Map<String, Object> customWithParam(@Selector String param) {
Map<String, Object> result = new HashMap<>();
result.put("param", param);
result.put("processed", "Processed: " + param);
return result;
}
@WriteOperation
public Map<String, Object> updateCustom(@Selector String param, @RequestBody Map<String, Object> body) {
Map<String, Object> result = new HashMap<>();
result.put("action", "update");
result.put("param", param);
result.put("body", body);
return result;
}
@DeleteOperation
public Map<String, Object> deleteCustom(@Selector String param) {
Map<String, Object> result = new HashMap<>();
result.put("action", "delete");
result.put("param", param);
return result;
}
}
// 带Web扩展的自定义端点
@Component
@WebEndpoint(id = "advanced-custom")
public class AdvancedCustomEndpoint {
@GetMapping("/details")
@ReadOperation
public WebEndpointResponse<Map<String, Object>> getDetails() {
Map<String, Object> details = new HashMap<>();
details.put("version", "1.0.0");
details.put("status", "active");
return new WebEndpointResponse<>(details, 200);
}
@PostMapping("/action")
@WriteOperation
public WebEndpointResponse<String> performAction(@RequestBody Map<String, Object> action) {
// 执行操作逻辑
return new WebEndpointResponse<>("Action performed successfully", 200);
}
}
业务指标端点
java
@Component
@Endpoint(id = "business-metrics")
public class BusinessMetricsEndpoint {
@Autowired
private MeterRegistry meterRegistry;
@ReadOperation
public Map<String, Object> businessMetrics() {
Map<String, Object> metrics = new HashMap<>();
// 获取业务指标
Counter orderCounter = meterRegistry.find("orders.total").counter();
if (orderCounter != null) {
metrics.put("totalOrders", orderCounter.count());
}
Timer orderTimer = meterRegistry.find("orders.processing.time").timer();
if (orderTimer != null) {
metrics.put("averageOrderProcessingTime", orderTimer.mean(Duration.ofMillis(1)));
}
Gauge activeSessions = meterRegistry.find("sessions.active").gauge();
if (activeSessions != null) {
metrics.put("activeSessions", activeSessions.value());
}
return metrics;
}
@ReadOperation
public Map<String, Object> businessMetricsByType(@Selector String type) {
Map<String, Object> metrics = new HashMap<>();
metrics.put("type", type);
switch (type.toLowerCase()) {
case "orders":
metrics.putAll(getOrderMetrics());
break;
case "users":
metrics.putAll(getUserMetrics());
break;
case "revenue":
metrics.putAll(getRevenueMetrics());
break;
default:
metrics.put("error", "Unknown metric type: " + type);
}
return metrics;
}
private Map<String, Object> getOrderMetrics() {
Map<String, Object> metrics = new HashMap<>();
// 获取订单相关指标
return metrics;
}
private Map<String, Object> getUserMetrics() {
Map<String, Object> metrics = new HashMap<>();
// 获取用户相关指标
return metrics;
}
private Map<String, Object> getRevenueMetrics() {
Map<String, Object> metrics = new HashMap<>();
// 获取收入相关指标
return metrics;
}
}
缓存端点
java
@Component
@Endpoint(id = "cache")
public class CacheEndpoint {
@Autowired
private CacheManager cacheManager;
@ReadOperation
public Map<String, Object> cacheInfo() {
Map<String, Object> result = new HashMap<>();
for (String cacheName : cacheManager.getCacheNames()) {
Cache cache = cacheManager.getCache(cacheName);
Map<String, Object> cacheInfo = new HashMap<>();
cacheInfo.put("name", cacheName);
cacheInfo.put("nativeCache", cache.getNativeCache().getClass().getSimpleName());
// 如果是Caffeine缓存,获取更多信息
if (cache.getNativeCache() instanceof com.github.benmanes.caffeine.cache.Cache) {
com.github.benmanes.caffeine.cache.Cache nativeCache =
(com.github.benmanes.caffeine.cache.Cache) cache.getNativeCache();
cacheInfo.put("estimatedSize", nativeCache.estimatedSize());
}
result.put(cacheName, cacheInfo);
}
return result;
}
@WriteOperation
public Map<String, Object> clearCache(@Selector String cacheName) {
Cache cache = cacheManager.getCache(cacheName);
if (cache != null) {
cache.clear();
return Map.of("message", "Cache '" + cacheName + "' cleared successfully");
} else {
return Map.of("error", "Cache '" + cacheName + "' not found");
}
}
@ReadOperation
public Map<String, Object> cacheStats(@Selector String cacheName) {
Map<String, Object> stats = new HashMap<>();
Cache cache = cacheManager.getCache(cacheName);
if (cache != null && cache.getNativeCache() instanceof com.github.benmanes.caffeine.cache.Cache) {
com.github.benmanes.caffeine.cache.Cache nativeCache =
(com.github.benmanes.caffeine.cache.Cache) cache.getNativeCache();
stats.put("cacheName", cacheName);
stats.put("estimatedSize", nativeCache.estimatedSize());
// 可以添加更多统计信息
} else {
stats.put("error", "Cache statistics not available for '" + cacheName + "'");
}
return stats;
}
}
安全配置
基本安全配置
java
@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 允许公开访问健康检查端点
.antMatchers("/actuator/health").permitAll()
// 允许公开访问应用信息端点
.antMatchers("/actuator/info").permitAll()
// 其他Actuator端点需要认证
.antMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic(); // 使用HTTP Basic认证
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin")
.password("{noop}admin123")
.roles("ADMIN");
}
}
// 基于角色的访问控制
@Configuration
public class RoleBasedSecurityConfig {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.pathMatchers("/actuator/health/**").permitAll()
.pathMatchers("/actuator/info/**").permitAll()
.pathMatchers("/actuator/metrics/**").hasRole("MONITOR")
.pathMatchers("/actuator/**").hasRole("ADMIN")
.anyExchange().authenticated()
.and()
.httpBasic()
.and()
.build();
}
}
端点访问控制
java
@Configuration
public class EndpointAccessConfig {
@Bean
public EndpointRequest.EndpointRequestMatcher endpointRequestMatcher() {
return EndpointRequest.toAnyEndpoint();
}
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
// 自定义端点访问决策
@Component
public class CustomEndpointAccessDecisionVoter implements AccessDecisionVoter<FilterInvocation> {
@Override
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof SecurityConfig &&
("ROLE_ADMIN".equals(attribute.getAttribute()) ||
"ROLE_MONITOR".equals(attribute.getAttribute()));
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
@Override
public int vote(Authentication authentication, FilterInvocation object,
Collection<ConfigAttribute> attributes) {
if (authentication == null) {
return ACCESS_DENIED;
}
// 检查用户是否有访问端点的权限
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
String requiredRole = attribute.getAttribute();
for (GrantedAuthority authority : authentication.getAuthorities()) {
if (requiredRole.equals(authority.getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
return ACCESS_DENIED;
}
}
监控集成
java
Prometheus集成
management:
metrics:
export:
prometheus:
enabled: true
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
java
@Configuration
public class PrometheusConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config()
.commonTags("application", "my-app")
.commonTags("instance", getInstanceId());
}
@Bean
public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig config) {
return new PrometheusMeterRegistry(config);
}
private String getInstanceId() {
// 获取实例ID的逻辑
return "instance-1";
}
}
// 自定义Prometheus指标
@Service
public class PrometheusMetricsService {
@Autowired
private MeterRegistry meterRegistry;
public void recordBusinessMetric(String name, double value, String... tags) {
Gauge.builder(name, () -> value)
.description("Business metric: " + name)
.tags(tags)
.register(meterRegistry);
}
public void incrementCounter(String name, String... tags) {
Counter.builder(name)
.description("Counter: " + name)
.tags(tags)
.register(meterRegistry)
.increment();
}
public void recordTimer(String name, Duration duration, String... tags) {
Timer.builder(name)
.description("Timer: " + name)
.tags(tags)
.register(meterRegistry)
.record(duration);
}
}
Grafana集成
java
@Configuration
public class GrafanaConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> grafanaMetrics() {
return registry -> registry.config()
.commonTags("service", "my-service")
.commonTags("environment", "production");
}
}
// Grafana仪表板配置
@Component
@Endpoint(id = "grafana")
public class GrafanaEndpoint {
@ReadOperation
public Map<String, Object> getDashboardConfig() {
Map<String, Object> dashboard = new HashMap<>();
dashboard.put("title", "Application Metrics Dashboard");
dashboard.put("description", "Spring Boot Actuator Metrics Dashboard");
List<Map<String, Object>> panels = new ArrayList<>();
// JVM内存面板
Map<String, Object> jvmMemoryPanel = new HashMap<>();
jvmMemoryPanel.put("title", "JVM Memory");
jvmMemoryPanel.put("type", "graph");
jvmMemoryPanel.put("targets", Arrays.asList(
Map.of("expr", "jvm_memory_used_bytes{area=\"heap\"}", "legendFormat", "Heap Used"),
Map.of("expr", "jvm_memory_used_bytes{area=\"nonheap\"}", "legendFormat", "Non-Heap Used")
));
panels.add(jvmMemoryPanel);
// HTTP请求面板
Map<String, Object> httpRequestsPanel = new HashMap<>();
httpRequestsPanel.put("title", "HTTP Requests");
httpRequestsPanel.put("type", "graph");
httpRequestsPanel.put("targets", Arrays.asList(
Map.of("expr", "http_server_requests_seconds_count", "legendFormat", "Total Requests"),
Map.of("expr", "http_server_requests_seconds_sum", "legendFormat", "Request Duration")
));
panels.add(httpRequestsPanel);
dashboard.put("panels", panels);
return dashboard;
}
}
生产环境配置
端点分组
java
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,configprops
exclude: shutdown,heapdump
base-path: /management
endpoint:
health:
show-details: when-authorized
probes:
enabled: true
metrics:
enabled: true
env:
show-values: when-authorized
group:
# 监控组 - 只读端点
monitor:
include: health,info,metrics
# 管理组 - 包含写操作端点
admin:
include: "*"
exclude: heapdump
健康探测
java
@Configuration
public class HealthProbesConfig {
@Bean
public HealthIndicator livenessIndicator() {
return () -> Health.up()
.withDetail("liveness", "Application is alive")
.build();
}
@Bean
public HealthIndicator readinessIndicator() {
return () -> {
// 检查应用是否准备好接收流量
boolean ready = checkReadiness();
if (ready) {
return Health.up()
.withDetail("readiness", "Application is ready")
.build();
} else {
return Health.down()
.withDetail("readiness", "Application is not ready")
.build();
}
};
}
private boolean checkReadiness() {
// 检查数据库连接、外部服务等
return true;
}
}
性能监控
java
@Configuration
public class PerformanceMonitoringConfig {
@Bean
public MeterRegistryCustomizer<MeterRegistry> performanceMetrics() {
return registry -> registry.config()
.meterFilter(MeterFilter.denyNameStartsWith("jvm"))
.meterFilter(MeterFilter.denyNameStartsWith("system"))
.meterFilter(MeterFilter.maximumAllowableMetrics(1000))
.meterFilter(MeterFilter.maximumAllowableTags("method", "uri", 100));
}
@Bean
public TimedAspect timedAspect(MeterRegistry meterRegistry) {
return new TimedAspect(meterRegistry,
new TimedAspectConfig()
.setEnabled(true)
.setAutoTimeRequests(true)
.setPercentiles(new double[]{0.5, 0.95, 0.99}));
}
}
故障排查
常见问题
1、端点无法访问
检查端点是否已暴露
验证安全配置
确认Base Path配置
2、指标数据不准确
检查MeterRegistry配置
验证指标命名规范
确认时间单位设置
3、健康检查失败
检查依赖服务的状态
验证数据库连接
查看应用日志
4、性能问题
监控端点响应时间
检查指标收集频率
优化端点暴露策略
调试配置
java
@Configuration
public class DebugConfig {
@Bean
public ApplicationEventListener<ContextRefreshedEvent> debugListener() {
return event -> {
ApplicationContext context = event.getApplicationContext();
// 打印所有端点信息
Map<String, Object> endpoints = context.getBeansWithAnnotation(Endpoint.class);
System.out.println("Available Endpoints:");
endpoints.forEach((name, bean) -> {
Endpoint endpoint = bean.getClass().getAnnotation(Endpoint.class);
System.out.println("- " + endpoint.id() + ": " + bean.getClass().getSimpleName());
});
};
}
}
// 端点访问日志
@Configuration
public class EndpointLoggingConfig {
@Bean
public FilterRegistrationBean<EndpointLoggingFilter> endpointLoggingFilter() {
FilterRegistrationBean<EndpointLoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new EndpointLoggingFilter());
registrationBean.addUrlPatterns("/actuator/*");
return registrationBean;
}
}
public class EndpointLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
long startTime = System.currentTimeMillis();
try {
chain.doFilter(request, response);
} finally {
long duration = System.currentTimeMillis() - startTime;
System.out.println("Endpoint " + httpRequest.getRequestURI() +
" took " + duration + "ms, status: " + httpResponse.getStatus());
}
}
}
最佳实践
1. 端点管理
根据环境选择合适的端点暴露策略
使用端点分组提高安全性
定期检查端点状态
2. 安全配置
实施最小权限原则
使用HTTPS保护端点通信
定期轮换认证凭据
3. 监控策略
定义关键指标和告警阈值
建立监控仪表板
实施自动化监控
4. 性能优化
控制指标收集频率
使用异步端点处理
实施缓存策略
5. 运维集成
与现有监控系统集成
建立自动化部署流程
实施日志聚合和分析