当前位置: 首页 > news >正文

自定义Spring Boot Actuator端点

自定义Spring Boot Actuator端点

引言

Spring Boot Actuator提供了生产级别的应用监控和管理功能,通过HTTP或JMX暴露应用的健康状态、指标信息、配置详情等。Actuator的可扩展性很强,开发者可以创建自定义端点来满足特定的监控和管理需求。本文将详细介绍如何开发自定义Actuator端点,包括信息端点、操作端点和自定义指标。

一、Actuator基础配置

1.1 依赖引入

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

1.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 Map<String, Object> getCacheInfo() { Map<String, Object> info = new HashMap<>(); info.put("caches", cacheManager.getCacheNames()); info.put("timestamp", Instant.now()); return info; } @ReadOperation public Map<String, 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 Map<String, String> clearCache(@Selector String name) { Cache<?> cache = cacheManager.getCache(name); if (cache != null) { cache.clear(); } return Map.of("status", "Cache cleared: " + name); } @DeleteOperation public Map<String, 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 List<OrderSummary> 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 Map<String, 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 Map<String, Object> getMemoryInfo() { Map<String, 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 Map<String, Object> memoryUsage( @Selector String type) { Map<String, 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(); Map<String, 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 List<String> 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 List<String> getCriticalServices() { return criticalServices; } public void setCriticalServices(List<String> criticalServices) { this.criticalServices = criticalServices; } } @Component @ConditionalOnEnabledHealthIndicator("custom") public class CompositeHealthIndicator extends CompositeHealthIndicatorFactory implements ReactiveHealthIndicator { private final CustomHealthProperties properties; public CompositeHealthIndicator(CustomHealthProperties properties, List<HealthIndicator> indicators) { super("custom"); this.properties = properties; indicators.forEach(this::registerIndicator); } @Override public Mono<Health> 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 List<AuditEvent> events = new ArrayList<>(); @Override public void add(AuditEvent event) { events.add(event); // 发送审计事件到消息队列 sendAuditEvent(event); } @Override public List<AuditEvent> 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端点的安全性也需要特别注意,应该通过适当的认证和授权机制保护敏感端点。

http://www.cnnetsun.cn/news/2443602.html

相关文章:

  • 2026年主流会议记录软件大横评,全场景实测对比,差距竟然这么大,黑马意外胜出
  • 【深度解析】Hermes Agent 0.14.0:本地代理、会话交接与自主工作流架构实践
  • 跨平台图形API实战选型:从Vulkan、DirectX到Metal与WebGPU的架构抉择
  • Cadence SPB17.4自动布线实战:从布局评估到DRC修复的完整避坑指南
  • 终极vscode-R插件完全指南:在Visual Studio Code中高效开发R语言
  • Seraphine英雄联盟战绩查询工具终极指南:智能排位助手完全教程
  • AI安全隐患排查系统:以智能技术筑牢安全生产防护网
  • 星思半导体:深耕芯片研发,助力卫星互联网产业高质量发展
  • 智能体状态管理:会话、上下文与检查点
  • 一种三维建筑物模型外轮廓的提取方法
  • AutoJs6:Android平台终极JavaScript自动化解决方案
  • *Python/Java/Go** 准备的详细指南,涵盖环境搭建、基础语法、实战项目(含代码)及避坑指南
  • RAG知识库生命周期①【第七篇】:文档新增修改删除,生产级向量同步更新方案
  • 云祺x鼎捷,为制造企业ERP打造双保险
  • 基于RAG架构的LLM知识库构建:从原理到实践
  • 告别人工抄表乱象!智能预付费系统实现用电管控全自动
  • 多智能体协同控制未来的前景和方向如何?
  • Spring AOP深度解析
  • NotebookLM实时协同黑科技:3个隐藏API+2个Chrome插件,让跨角色协作响应提速83%
  • 重新定义视频学习:Bili2Text如何将B站内容转化为结构化知识库
  • 魔兽争霸III终极兼容性增强插件:WarcraftHelper完整指南
  • 惠普游戏本性能解放:OmenSuperHub开源工具深度解析与实战指南
  • 关于变量赋值失败,yn有话说
  • 你的小米路由器安全吗?聊聊Nginx配置不当那些事儿(附自查清单)
  • 期刊论文发表提速:虎贲等考 AI,让核心期刊写作更规范、更高效、更容易中稿
  • 自动增益控制与灵敏度时间控制:从原理到工程实践
  • FreeRTOS SMP多核调试踩坑记:在TC397上如何确认你的任务真的跑在了对的CPU核心?
  • 如何用GrasscutterCommandGenerator轻松管理原神私服?新手快速入门指南
  • 如何用Highlighter打造永不消失的网页标记:终极网页高亮工具使用指南
  • Unity游戏自动翻译终极指南:XUnity.AutoTranslator完整教程 [特殊字符][特殊字符]