自定义Spring Boot Actuator端点
自定义Spring Boot Actuator端点引言Spring Boot Actuator提供了生产级别的应用监控和管理功能通过HTTP或JMX暴露应用的健康状态、指标信息、配置详情等。Actuator的可扩展性很强开发者可以创建自定义端点来满足特定的监控和管理需求。本文将详细介绍如何开发自定义Actuator端点包括信息端点、操作端点和自定义指标。一、Actuator基础配置1.1 依赖引入dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency1.2 端点配置management: endpoints: web: exposure: include: health,info,metrics,prometheus exclude: env,beans base-path: /actuator mapping: health: /healthcheck endpoint: health: show-details: when-authorized probes: enabled: true info: enabled: true info: env: enabled: true health: db: enabled: true redis: enabled: true二、自定义信息端点2.1 静态信息端点Component public class CustomInfoContributor implements InfoContributor { Override public void contribute(Info.Builder builder) { builder.withDetail(application, Map.of( name, my-app, version, 1.0.0, description, Custom application )); builder.withDetail(git, Map.of( branch, main, commit, abc123def )); } }2.2 动态信息端点Component public class BuildInfoContributor implements InfoContributor { private final Build build; public BuildInfoContributor(ApplicationContext context) { this.build context.getBean(buildInfo, Build.class); } Override public void contribute(Info.Builder builder) { builder.withDetail(build, Map.of( artifact, build.getArtifact(), group, build.getGroup(), version, build.getVersion(), time, build.getTime().toString() )); } }三、自定义操作端点3.1 创建操作端点Component Endpoint(id cache, enableByDefault true) public class CacheManagementEndpoint { private final CacheManager cacheManager; public CacheManagementEndpoint(CacheManager cacheManager) { this.cacheManager cacheManager; } ReadOperation public MapString, Object getCacheInfo() { MapString, Object info new HashMap(); info.put(caches, cacheManager.getCacheNames()); info.put(timestamp, Instant.now()); return info; } ReadOperation public MapString, Object getCacheDetails(Selector String name) { Cache? cache cacheManager.getCache(name); if (cache null) { return Map.of(error, Cache not found: name); } return Map.of( name, cache.getName(), type, cache.getClass().getSimpleName() ); } WriteOperation public MapString, String clearCache(Selector String name) { Cache? cache cacheManager.getCache(name); if (cache ! null) { cache.clear(); } return Map.of(status, Cache cleared: name); } DeleteOperation public MapString, String evictCache(Selector String name) { cacheManager.removeCache(name); return Map.of(status, Cache evicted: name); } }3.2 复杂参数端点Component Endpoint(id orders, enableByDefault false) public class OrderManagementEndpoint { private final OrderService orderService; public OrderManagementEndpoint(OrderService orderService) { this.orderService orderService; } ReadOperation public ListOrderSummary getOrders( Selector DateTimeFormat(iso ISO.DATE) LocalDate startDate, Selector DateTimeFormat(iso ISO.DATE) LocalDate endDate, Selector(required false) OrderStatus status) { return orderService.findOrders(startDate, endDate, status); } WriteOperation public MapString, Object processOrder( Selector Long orderId, Selector String action) { if (cancel.equals(action)) { orderService.cancelOrder(orderId); return Map.of(status, cancelled, orderId, orderId); } else if (complete.equals(action)) { orderService.completeOrder(orderId); return Map.of(status, completed, orderId, orderId); } return Map.of(error, Unknown action: action); } }四、JMX端点4.1 JMX端点配置JmxEndpoint(id memory) public class MemoryJmxEndpoint { private final Runtime runtime; public MemoryJmxEndpoint() { this.runtime Runtime.getRuntime(); } ReadOperation public MapString, Object getMemoryInfo() { MapString, Object info new HashMap(); info.put(totalMemory, runtime.totalMemory()); info.put(freeMemory, runtime.freeMemory()); info.put(usedMemory, runtime.totalMemory() - runtime.freeMemory()); info.put(maxMemory, runtime.maxMemory()); return info; } WriteOperation public String triggerGC() { System.gc(); return GC triggered; } WriteOperation public MapString, Object memoryUsage( Selector String type) { MapString, Object result new HashMap(); if (heap.equals(type)) { MemoryMXBean memoryMXBean ManagementFactory.getMemoryMXBean(); MemoryUsage heapUsage memoryMXBean.getHeapMemoryUsage(); result.put(init, heapUsage.getInit()); result.put(used, heapUsage.getUsed()); result.put(committed, heapUsage.getCommitted()); result.put(max, heapUsage.getMax()); } else if (nonheap.equals(type)) { MemoryMXBean memoryMXBean ManagementFactory.getMemoryMXBean(); MemoryUsage nonHeapUsage memoryMXBean.getNonHeapMemoryUsage(); result.put(init, nonHeapUsage.getInit()); result.put(used, nonHeapUsage.getUsed()); result.put(committed, nonHeapUsage.getCommitted()); result.put(max, nonHeapUsage.getMax()); } return result; } }五、自定义健康指标5.1 简单健康指标Component public class CustomHealthIndicator implements HealthIndicator { private final DatabaseService databaseService; private final ExternalApiService externalApiService; public CustomHealthIndicator(DatabaseService databaseService, ExternalApiService externalApiService) { this.databaseService databaseService; this.externalApiService externalApiService; } Override public Health health() { try { boolean dbHealthy databaseService.checkHealth(); boolean apiHealthy externalApiService.checkHealth(); MapString, HealthIndicator indicators new HashMap(); indicators.put(database, dbHealthy ? Health.up().build() : Health.down().withDetail(error, DB connection failed).build()); indicators.put(externalApi, apiHealthy ? Health.up().build() : Health.down().withDetail(error, API timeout).build()); boolean allHealthy dbHealthy apiHealthy; Health.Builder builder allHealthy ? Health.up() : Health.down(); return builder .withDetails(indicators.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e - e.getValue().getDetails() ))) .build(); } catch (Exception e) { return Health.down() .withException(e) .build(); } } }5.2 可配置健康指标ConfigurationProperties(prefix health.custom) public class CustomHealthProperties { private boolean enabled true; private int timeout 5000; private ListString criticalServices Arrays.asList(database); public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled enabled; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout timeout; } public ListString getCriticalServices() { return criticalServices; } public void setCriticalServices(ListString criticalServices) { this.criticalServices criticalServices; } } Component ConditionalOnEnabledHealthIndicator(custom) public class CompositeHealthIndicator extends CompositeHealthIndicatorFactory implements ReactiveHealthIndicator { private final CustomHealthProperties properties; public CompositeHealthIndicator(CustomHealthProperties properties, ListHealthIndicator indicators) { super(custom); this.properties properties; indicators.forEach(this::registerIndicator); } Override public MonoHealth health() { return executeHealthReactive(); } }六、自定义指标6.1 Micrometer指标Service public class BusinessMetrics { private final MeterRegistry meterRegistry; private final Counter orderCounter; private final Timer orderTimer; private final DistributionSummary orderAmountSummary; public BusinessMetrics(MeterRegistry meterRegistry) { this.meterRegistry meterRegistry; this.orderCounter Counter.builder(orders.created) .description(Number of orders created) .tag(type, online) .register(meterRegistry); this.orderTimer Timer.builder(orders.processing.time) .description(Order processing duration) .publishPercentiles(0.5, 0.95, 0.99) .register(meterRegistry); this.orderAmountSummary DistributionSummary .builder(orders.amount) .description(Order amount distribution) .publishPercentiles(0.5, 0.95, 0.99) .register(meterRegistry); } public void recordOrder(Order order) { orderCounter.increment(); long startTime System.currentTimeMillis(); try { // 订单处理逻辑 } finally { orderTimer.record(System.currentTimeMillis() - startTime, TimeUnit.MILLISECONDS); } orderAmountSummary.record(order.getAmount().doubleValue()); } }6.2 Gauge指标Service public class SystemMetrics { private final MeterRegistry meterRegistry; private final AtomicInteger activeConnections; public SystemMetrics(MeterRegistry meterRegistry) { this.meterRegistry meterRegistry; this.activeConnections new AtomicInteger(0); // 注册Gauge Gauge.builder(app.connections.active, activeConnections, AtomicInteger::get) .description(Active connections) .register(meterRegistry); Gauge.builder(app.memory.used, Runtime.getRuntime(), Runtime::totalMemory) .description(Used memory) .register(meterRegistry); Gauge.builder(app.memory.free, Runtime.getRuntime(), Runtime::freeMemory) .description(Free memory) .register(meterRegistry); } public void incrementConnections() { activeConnections.incrementAndGet(); } public void decrementConnections() { activeConnections.decrementAndGet(); } }七、响应过滤器7.1 自定义过滤器Component Order(Ordered.HIGHEST_PRECEDENCE) public class ActuatorSecurityFilter extends OncePerRequestFilter { private final SecurityService securityService; public ActuatorSecurityFilter(SecurityService securityService) { this.securityService securityService; } Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String path request.getRequestURI(); if (path.startsWith(/actuator/)) { if (!securityService.hasAccess(request)) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); return; } response.setHeader(X-Content-Type-Options, nosniff); response.setHeader(X-Frame-Options, DENY); } filterChain.doFilter(request, response); } }8.2 审计事件Component public class ActuatorAuditService implements AuditEventRepository { private final ListAuditEvent events new ArrayList(); Override public void add(AuditEvent event) { events.add(event); // 发送审计事件到消息队列 sendAuditEvent(event); } Override public ListAuditEvent find(String principal, Instant after, String type) { return events.stream() .filter(e - principal null || e.getPrincipal().equals(principal)) .filter(e - after null || e.getTimestamp().isAfter(after)) .filter(e - type null || e.getType().equals(type)) .collect(Collectors.toList()); } private void sendAuditEvent(AuditEvent event) { // 发送审计事件逻辑 } }总结Spring Boot Actuator提供了强大的可扩展机制开发者可以创建自定义端点、健康指标和指标收集器来满足特定的监控需求。合理使用Actuator可以构建完整的应用可观测性体系包括健康检查、性能指标、日志追踪等。在生产环境中Actuator端点的安全性也需要特别注意应该通过适当的认证和授权机制保护敏感端点。