目录
Actuator概述
Actuator功能
Spring Boot Actuator提供了生产就绪的功能,帮助您监控和管理Spring Boot应用程序。
核心功能:
- 健康检查: 应用程序和依赖服务的健康状态
- 指标收集: 应用程序的性能指标和业务指标
- 端点暴露: HTTP/JMX端点获取应用程序信息
- 日志管理: 动态日志级别调整和日志查看
- 环境信息: 配置属性、系统属性、环境变量
Maven依赖配置
<dependencies>
<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.7.5</version>
</dependency>
<!-- Micrometer for metrics -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>1.9.5</version>
</dependency>
<!-- Prometheus metrics -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.9.5</version>
</dependency>
<!-- JMX support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
基础配置
application.yml配置
management:
endpoints:
web:
exposure:
include: "*" # 在生产环境中应该仅暴露必要的端点
exclude: shutdown
base-path: /actuator
path-mapping:
health: health-check
endpoint:
health:
show-details: always
show-components: always
info:
enabled: true
metrics:
enabled: true
prometheus:
enabled: true
info:
env:
enabled: true
java:
enabled: true
git:
mode: full
build:
enabled: true
# 应用程序信息
info:
app:
name: Spring MVC Application
description: 基于Spring MVC的企业级应用
version: 1.0.0
developer: Your Team
java:
vendor: ${java.vendor}
version: ${java.version}
logging:
level:
org.springframework.boot.actuator: INFO
端点配置
内置端点管理
基础端点配置
@Configuration
public class ActuatorConfig {
@Bean
public EndpointMappingCustomEndpointMappingCustomizer endpointMappingCustomizer() {
return endpointMapping -> {
endpointMapping.setPrefix("/api/admin"); // 改变端点前缀
};
}
// 自定义端点
@Component
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> custom() {
Map<String, Object> result = new HashMap<>();
result.put("timestamp", LocalDateTime.now());
result.put("application", "Spring MVC App");
result.put("status", "running");
return result;
}
@WriteOperation
public Map<String, Object> customWrite(String parameter) {
Map<String, Object> result = new HashMap<>();
result.put("parameter", parameter);
result.put("timestamp", LocalDateTime.now());
return result;
}
}
// 控制器端点(简化HTTP方法)
@RestControllerEndpoint(id = "customcontroller")
public class CustomControllerEndpoint {
@GetMapping("/custom-controller")
public ResponseEntity<Map<String, Object>> customEndpoint() {
Map<String, Object> result = new HashMap<>();
result.put("message", "自定义控制器端点");
result.put("timestamp", LocalDateTime.now());
return ResponseEntity.ok(result);
}
}
}
Web端点安全
端点安全配置
@Configuration
public class ActuatorSecurityConfig {
@Bean
public SecurityFilterChain actuatorFilterChain(HttpSecurity http) throws Exception {
http
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests(authorize ->
authorize
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.requestMatchers(EndpointRequest.to("prometheus")).hasRole("METRICS")
.requestMatchers(EndpointRequest.to("shutdown")).hasRole("ADMIN")
.anyRequest().authenticated())
.httpBasic(withDefaults());
return http.build();
}
}
// 信息端点自定义
@Component
public class CustomInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("custom", Map.of(
"deployedBy", "DevOps Team",
"deploymentTime", LocalDateTime.now(),
"environment", "Production",
"instanceId", System.getProperty("instance.id", "unknown")
));
}
}
健康检查
内置健康指示器
健康检查配置
@Configuration
public class HealthConfig {
@Autowired
private DataSource dataSource;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 数据库健康指示器
@Bean
public HealthIndicator databaseHealthIndicator() {
return () -> {
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
String database = metaData.getDatabaseProductName();
return Health.up()
.withDetail("database", database)
.withDetail("version", metaData.getDatabaseProductVersion())
.withDetail("url", metaData.getURL())
.build();
} catch (Exception e) {
return Health.down()
.withDetail("database", "Unknown")
.withDetail("error", e.getMessage())
.build();
}
};
}
// Redis健康指示器
@Bean
public HealthIndicator redisHealthIndicator() {
return () -> {
try {
String pong = redisTemplate.getConnectionFactory()
.getConnection()
.ping();
return Health.up()
.withDetail("redis", "Redis")
.withDetail("ping", pong)
.build();
} catch (Exception e) {
return Health.down()
.withDetail("redis", "Redis")
.withDetail("error", e.getMessage())
.build();
}
};
}
// 外部API健康检查
@Component
public class ExternalApiHealthIndicator implements HealthIndicator {
@Autowired
private RestTemplate restTemplate;
@Override
public健康状况 health() {
try {
ResponseEntity<String> response = restTemplate.getForEntity(
"https://api.external.com/health", String.class);
if (response.getStatusCode().is2xxSuccessful()) {
return Health.up()
.withDetail("externalApi", "https://api.external.com/health")
.withDetail("status", "Available")
.build();
} else {
return Health.down()
.withDetail("externalApi", "https://api.external.com/health")
.withDetail("status", "Unavailable")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("externalApi", "https://api.external.com/health")
.withDetail("error", e.getMessage())
.build();
}
}
}
// 自定义业务健康检查
@Component
public class BusinessHealthIndicator implements HealthIndicator {
@Autowired
private UserService userService;
@Autowired
private OrderService orderService;
@Override
public Health health() {
try {
// 检查用户服务
long userCount = userService.getTotalUserCount();
boolean canCreateUser = userCount < 1000000; // 业务规则:用户数量限制
// 检查订单服务
long pendingOrders = orderService.getPendingOrderCount();
boolean ordersHealthy = pendingOrders < 10000; // 业务规则:待处理订单限制
if (canCreateUser && ordersHealthy) {
return Health.up()
.withDetail("userService", "Healthy")
.withDetail("orderService", "Healthy")
.withDetail("totalUsers", userCount)
.withDetail("pendingOrders", pendingOrders)
.build();
} else {
return Health.down()
.withDetail("userService", canCreateUser ? "Healthy" : "Overloaded")
.withDetail("orderService", ordersHealthy ? "Healthy" : "Overloaded")
.withDetail("totalUsers", userCount)
.withDetail("pendingOrders", pendingOrders)
.withDetail("reason", "Business rules violated")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.withDetail("businessHealth", "Failed")
.build();
}
}
}
}
健康检查通知
健康状态变更通知
@Component
public class HealthStatusNotifier {
private static final Logger logger = LoggerFactory.getLogger(HealthStatusNotifier.class);
private final Map<String, Health> previousStatus = new HashMap<>();
@EventListener
public void onHealthStatusChange(HealthStatusChangeEvent event) {
String healthIndicatorName = event.getHealthIndicatorName();
Health currentHealth = event.getHealth();
Health previousHealthStatus = previousStatus.get(healthIndicatorName);
if (previousHealthStatus != null &&
!previousHealthStatus.getStatus().equals(currentHealth.getStatus())) {
logHealthStatusChange(healthIndicatorName, previousHealthStatus, currentHealth);
// 发送通知
sendHealthNotification(healthIndicatorName, previousHealthStatus, currentHealth);
}
previousStatus.put(healthIndicatorName, currentHealth);
}
private void logHealthStatusChange(String name, Health previous, Health current) {
logger.warn("健康状态变更 - {}: {} -> {}",
name, previous.getStatus(), current.getStatus());
}
private void sendHealthNotification(String name, Health previous, Health current) {
// 发送邮件通知
emailService.sendHealthAlert(name, previous.getStatus(), current.getStatus());
// 发送Slack通知
slackService.sendHealthAlert(name, previous.getStatus(), current.getStatus());
// 记录到监控系统
monitoringService.recordHealthEvent(name, previous, current);
}
}
指标监控
Micrometer指标
自定义指标配置
@Configuration
public class MetricsConfig {
@Bean
public MeterRegistry meterRegistry() {
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
return registry;
}
@Bean
public TimedAspect timedAspect(MeterRegistry meterRegistry) {
return new TimedAspect(meterRegistry);
}
@Bean
public CountedAspect countedAspect(MeterRegistry meterRegistry) {
return new CountedAspect(meterRegistry);
}
}
@Service
public class BusinessMetricsService {
private final MeterRegistry meterRegistry;
private final Counter userRegistrationCounter;
private final Counter orderCreationCounter;
private final Timer orderProcessingTimer;
private final Gauge activeUsersGauge;
public BusinessMetricsService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
// 用户注册计数器
this.userRegistrationCounter = Counter.builder("user.registrations")
.description("用户注册总数")
.tag("application", "ecommerce")
.register(meterRegistry);
// 订单创建计数器
this.orderCreationCounter = Counter.builder("orders.created")
.description("订单创建总数")
.tag("application", "ecommerce")
.register(meterRegistry);
// 订单处理计时器
this.orderProcessingTimer = Timer.builder("orders.processing.time")
.description("订单处理耗时")
.tag("application", "ecommerce")
.register(meterRegistry);
// 活跃用户数仪表
this.activeUsersGauge = Gauge.builder("users.active")
.description("当前活跃用户数")
.tag("application", "ecommerce")
.register(meterRegistry, this, BusinessMetricsService::getActiveUserCount);
}
public void recordUserRegistration(String userType) {
userRegistrationCounter.increment(
Tags.of("user.type", userType)
);
}
public void recordOrderCreation(String orderType, BigDecimal amount) {
orderCreationCounter.increment(
Tags.of("order.type", orderType,
"amount.range", categorizeAmount(amount))
);
}
public void recordOrderProcessingTime(Duration processingTime, String orderType) {
orderProcessingTimer.record(processingTime,
Tags.of("order.type", orderType)
);
}
private double getActiveUserCount() {
// 返回当前活跃用户数
return userService.getActiveUserCount();
}
private String categorizeAmount(BigDecimal amount) {
if (amount.compareTo(new BigDecimal("100")) < 0) {
return "low";
} else if (amount.compareTo(new BigDecimal("500")) < 0) {
return "medium";
} else {
return "high";
}
}
}
// 使用注解自动指标收集
@Timed(description = "用户搜索耗时")
@Counted(description = "用户搜索次数")
@RestController
public class UserController {
@GetMapping("/users/search")
public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {
// 自动记录执行时间和调用次数
List<User> users = userService.searchUsers(keyword);
// 记录业务指标
businessMetrics.recordUserSearch(keyword, users.size());
return ResponseEntity.ok(users);
}
}
生产环境配置
生产环境安全配置
生产环境配置
# application-prod.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
exclude: shutdown,env,configprops
base-path: /actuator
endpoint:
health:
show-details: when-authorized
show-components: never
shutdown:
enabled: false
env:
show-values: never
configprops:
show-values: never
info:
env:
enabled: false
java:
enabled: false
git:
mode: simple
security:
enabled: true
roles: ADMIN,METRICS
server:
port: 8081
servlet:
context-path: /management
# 日志配置
logging:
level:
org.springframework.boot.actuator: WARN
org.springframework.security: WARN
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# 指标配置
management:
metrics:
export:
prometheus:
enabled: true
step: 30s
distribution:
percentiles-histogram:
"[http.server.requests]": true
sla:
"[http.server.requests]": 50ms, 100ms, 200ms, 500ms, 1s, 2s, 5s
tags:
application: ${spring.application.name:unknown}
instance: ${HOSTNAME:unknown}
自定义安全配置
生产环境安全
@Configuration
@Profile("prod")
public class ProductionActuatorSecurityConfig {
@Value("${management.security.username:admin}")
private String actuatorUsername;
@Value("${management.security.password}")
private String actuatorPassword;
@Bean
@Primary
public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
http
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests(authorize ->
authorize
.requestMatchers(EndpointRequest.to("health")).permitAll()
.requestMatchers(EndpointRequest.to("info")).permitAll()
.requestMatchers(EndpointRequest.to("prometheus")).hasRole("METRICS")
.requestMatchers(EndpointRequest.toPattern("heapdump")).hasRole("ADMIN")
.requestMatchers(EndpointRequest.toClass(ShutdownEndpoint.class)).hasRole("SUPER_ADMIN")
.anyRequest().authenticated()
)
.httpBasic(withDefaults())
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.csrf(csrf -> csrf.disable());
return http.build();
}
@Bean
public InMemoryUserDetailsManager actuatorUserDetailsManager() {
UserDetails metricsUser = User.withDefaultPasswordEncoder()
.username(actuatorUsername)
.password(actuatorPassword)
.roles("METRICS", "ADMIN")
.build();
return new InMemoryUserDetailsManager(metricsUser);
}
}
Prometheus监控
Prometheus配置
prometheus.yml配置
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "alert_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
scrape_configs:
- job_name: 'spring-mvc-app'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/actuator/prometheus'
scrape_interval: 10s
- job_name: 'spring-actuator'
static_configs:
- targets: ['localhost:8081']
metrics_path: '/actuator/prometheus'
scrape_interval: 10s
basic_auth:
username: 'metrics'
password: 'metrics123'
告警规则配置
# alert_rules.yml
groups:
- name: spring-mvc-alerts
rules:
- alert: HighErrorRate
expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) > 0.1
for: 2m
labels:
severity: critical
annotations:
summary: "高错误率告警"
description: "应用错误率超过10%"
- alert: HighMemoryUsage
expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "内存使用率告警"
description: "应用内存使用率超过80%"
- alert: ApplicationDown
expr: up{job="spring-mvc-app"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "应用宕机告警"
description: "应用服务不可访问"
- alert: HighResponseTime
expr: histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m])) > 2
for: 3m
labels:
severity: warning
annotations:
summary: "响应时间告警"
description: "95%的请求响应时间超过2秒"
Grafana可视化
仪表板配置
应用监控仪表板:
{
"dashboard": {
"title": "Spring MVC Application Monitoring",
"panels": [
{
"title": "请求速率",
"type": "graph",
"targets": [
{
"expr": "rate(http_server_requests_seconds_count[5m])",
"legendFormat": "{{method}} {{uri}}"
}
]
},
{
"title": "响应时间",
"type": "graph",
"targets": [
{
"expr": "histogram_quantile(0.50, rate(http_server_requests_seconds_bucket[5m]))",
"legendFormat": "50th percentile"
},
{
"expr": "histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m]))",
"legendFormat": "95th percentile"
}
]
},
{
"title": "JVM内存使用",
"type": "graph",
"targets": [
{
"expr": "jvm_memory_used_bytes{area=\"heap\"}",
"legendFormat": "Heap Used"
},
{
"expr": "jvm_memory_max_bytes{area=\"heap\"}",
"legendFormat": "Heap Max"
}
]
},
{
"title": "活跃用户",
"type": "stat",
"targets": [
{
"expr": "users_active",
"legendFormat": "Active Users"
}
]
}
]
}
}
总结
Spring Boot Actuator为企业级应用提供了完整的生产监控解决方案:
核心技术要点
- 端点管理 - 丰富的应用程序信息暴露
- 健康检查 - 依赖服务和业务逻辑监控
- 指标收集 - 全面的应用程序性能指标
- 自定义指标 - 业务特定的监控指标
- Prometheus集成 - 时序数据存储和分析
- Grafana可视化 - 直观的监控仪表板
- 告警机制 - 主动的问题检测和通知
生产环境价值
- 可观测性:全面的应用程序监控能力
- 问题诊断:快速定位和解决生产问题
- 性能优化:基于数据的性能调优
- 业务监控:业务指标与系统指标关联
最佳实践建议
- 安全性:严格限制端点的访问权限
- 性能影响:选择低开销的指标收集方式
- 数据处理:合理设置指标采样和聚合
- 告警设计:设置合理的告警阈值和沉默期
- 存储优化:配置适当的指标保留时间
通过这些教程的深入学习,您已经构建了一个完整的Spring MVC技术栈知识体系,具备了企业级应用开发的全面能力!
1748

被折叠的 条评论
为什么被折叠?



