服务上线了可你心里没底它到底活没活着内存泄漏没最近请求吞吐怎样用户已经投诉接口慢你却连服务挂了都不知道。监控不是上线后的锦上添花而是保命的底线。本文用 Spring Boot 4.1 的 Actuator 从零搭一套生产监控健康检查、指标采集、自定义探针、配合 Prometheus 告警让你半夜手机不乱响、服务出事第一时间知道。看完你就能动手复现一套能上线的监控方案。一、这个问题到底是什么上线不等于结束恰恰是运维噩梦的开始。很多团队把代码写完、部署到生产就觉得万事大吉结果服务半夜悄悄挂掉第二天早上用户打爆电话才发现。问题出在哪没有任何手段主动、及时地感知服务的运行状态。你要回答三个问题服务还活着吗服务状态好不好服务什么时候开始变差的这三个问题对应监控的三种能力健康检查Health、指标采集Metrics、告警通知Alerting。在没有监控的世界里你只能靠用户投诉、靠凌晨被叫醒、靠重启一下试试这种玄学来运维。而有了监控你能在问题发生的几分钟内知道甚至能在问题爆发前就收到预警。Spring Boot 官方自带的 Actuator 就是干这个的——它把服务的健康、指标、配置、日志等状态全部暴露成接口配合可视化工具和告警系统就能搭出一套完整的生产监控。这个场景几乎所有 Java 后端团队都会遇到服务一多、实例一多人工盯不过来必须靠自动化监控。Actuator 是目前 Spring Boot 生态里最官方、最成熟、接入成本最低的监控方案没有之一。二、底层原理到底怎么回事Actuator 的原理可以一句话说清它把 Spring Boot 应用运行时的各种状态通过一个个 HTTP 端点Endpoint暴露出来。你访问一个 URL就能拿到 JSON 格式的服务状态数据。拿健康检查举例。你请求/actuator/healthActuator 会依次检查应用依赖的各种组件是否正常——数据库连不连得上、Redis 通不通、磁盘空间够不够。每个组件是一个检查器HealthIndicator检查结果汇总成一个整体状态UP健康、DOWN不健康、OUT_OF_SERVICE停用、UNKNOWN未知。class HealthIndicator { Health health() // 每个检查器返回自己那块组件是否正常 } // 多个检查器结果汇总 - 整体 health 状态关键在于整体状态怎么算出来。Actuator 默认用StatusAggregator来聚合只要任何一个关键检查器返回 DOWN整体就是 DOWN。这意味着只要数据库断了健康检查立刻返回 500 或 503负载均衡器/容器编排系统比如健康检查探针就能马上把流量摘掉不把请求打到坏实例上。指标采集的原理类似。Actuator 内部从 Spring 的ApplicationContext、JVM、数据源等地方收集数据形成一个个计量器Meter比如jvm.memory.usedJVM 已用内存、http.server.requestsHTTP 请求数/耗时、processed.files已处理文件数。这些指标通过 Micrometer 这个门面库统一暴露——Micrometer 是 Actuator 和监控系统之间的桥梁它定义了一套统一的指标模型后端可以是 Prometheus、Graphite、InfluxDB 等任意支持的系统。为什么用 Micrometer因为如果 Actuator 直接对接每个监控系统那可维护性就崩了——Prometheus 一套代码、Graphite 又一套。Micrometer 提供统一的MeterRegistry接口你只需要在任意指标采集器上注册不同的 registry 实现即可。写业务代码时根本不需要关心后端是哪个监控系统。告警的原理则是外围联动Actuator 本身只暴露数据不主动发短信、打电话。你要把 Prometheus 之类的监控系统接入 Actuator 暴露的指标端点让它定时抓取数据然后配置告警规则——比如连续 3 分钟http.server.requests的平均耗时超过 500ms 就告警。告警动作发邮件、发钉钉、发企业微信由 Prometheus 或其配套的 Alertmanager 负责Actuator 只负责把数据送出来。一句话总结原理Actuator 状态数据的水龙头Micrometer 数据的统一管道Prometheus 数据的蓄水池和告警大脑。三者配合形成监控闭环。三、实战手把手写代码我们搭一个最小可用的生产监控一个带数据库的 Spring Boot 服务暴露健康检查和指标配合 Prometheus 抓取并做告警。全程只需要一个项目 一个 docker-compose 文件。3.1 完整工程结构先看目录结构demo-monitor/ ├── pom.xml ├── docker-compose.yml └── src/main/ ├── java/com/example/monitor/ │ ├── DemoMonitorApplication.java │ └── controller/OrderController.java └── resources/application.yml3.2 pom.xml完整可运行?xml version1.0 encodingUTF-8?projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion4.1.1/versionrelativePath//parentgroupIdcom.example/groupIdartifactIddemo-monitor/artifactIdversion1.0.0/versionnamedemo-monitor/namedescriptionSpring Boot Actuator 生产监控 demo/descriptionpropertiesjava.version21/java.version/propertiesdependencies!-- Web 应用 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- Actuator 监控核心 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!-- 接入 Prometheus 的适配器Micrometer 的 registry 实现 --dependencygroupIdio.micrometer/groupIdartifactIdmicrometer-registry-prometheus/artifactId/dependency!-- 数据库访问让健康检查能检查 MySQL 连接 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project这段配置里最关键的是三个依赖spring-boot-starter-actuator开启了监控能力micrometer-registry-prometheus让指标能按 Prometheus 的文本格式输出否则你拿不到/actuator/prometheus这个端点spring-boot-starter-data-jpa加上 MySQL 驱动是为了让健康检查真的去连一次数据库这样数据库断了监控能立刻发现。3.3 启动类完整packagecom.example.monitor;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassDemoMonitorApplication{publicstaticvoidmain(String[]args){SpringApplication.run(DemoMonitorApplication.class,args);}}3.4 订单接口完整用来产生真实的 HTTP 指标packagecom.example.monitor.controller;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.ThreadLocalRandom;RestControllerRequestMapping(/api/order)publicclassOrderController{/** * 模拟查询订单详情随机睡眠 50~300ms 制造可观测的耗时分布 */GetMapping(/{id})publicMapString,ObjectqueryOrder(PathVariableLongid)throwsInterruptedException{// 模拟真实业务处理耗时让 http.server.requests 指标有起伏可观察Thread.sleep(ThreadLocalRandom.current().nextLong(50,300));MapString,ObjectresultnewHashMap();result.put(id,id);result.put(status,PAID);result.put(amount,ThreadLocalRandom.current().nextDouble(10,1000));returnresult;}}这个接口故意加了随机的Thread.sleep是为了让后面的指标在 Prometheus 里能看出明显波动。真实项目里它就是你的业务接口会自然产生请求数和耗时指标。3.5 application.yml完整server:port:8080spring:application:name:demo-monitordatasource:url:jdbc:mysql://localhost:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/Shanghaiusername:rootpassword:root123456driver-class-name:com.mysql.cj.jdbc.Driverjpa:hibernate:ddl-auto:noneshow-sql:falsemanagement:endpoints:web:exposure:# 只暴露我们需要的端点生产环境不要用 *全暴露有安全风险include:health,info,metrics,prometheusendpoint:health:# 健康检查显示详细内容哪些组件、每个组件的状态show-details:always# 指标里带上应用名和应用实例 tag方便 Prometheus 按应用区分metrics:tags:application:${spring.application.name}这里有一个生产级的关键细节management.endpoints.web.exposure.include不要写成*。全暴露会把/actuator/env、/actuator/heapdump这种敏感端点点开外人能看到环境变量甚至下载堆转储极其危险。只暴露 health、info、metrics、prometheus 这四个就够用了。3.6 docker-compose.yml启动 MySQL 和 Prometheus完整version:3.8services:mysql:image:mysql:8.4environment:MYSQL_ROOT_PASSWORD:root123456MYSQL_DATABASE:demoports:-3306:3306prometheus:image:prom/prometheus:v3.1.0volumes:-./prometheus.yml:/etc/prometheus/prometheus.ymlports:-9090:9090配套的prometheus.yml让 Prometheus 每 15 秒来你的服务抓一次指标global:scrape_interval:15sscrape_configs:-job_name:demo-monitormetrics_path:/actuator/prometheusstatic_configs:-targets:[host.docker.internal:8080]注意metrics_path指向/actuator/prometheus端口是服务本身的 8080因为 Prometheus 要主动来抓你服务的指标。host.docker.internal是让容器里的 Prometheus 能访问宿主机的服务地址。3.7 动手验证按顺序执行先docker compose up -d mysql启动数据库Prometheus 可以先不启动先看 Actuator 本身。启动 Spring Boot 应用mvn spring-boot:run。浏览器访问http://localhost:8080/actuator/health会看到类似这样的 JSON{status:UP,components:{db:{status:UP},diskSpace:{status:UP},ping:{status:UP}}}status: UP说明整体健康components里逐项列出数据库、磁盘、ping 各自的状态。现在把 MySQL 停掉docker compose stop mysql再刷新健康检查你会看到status变成DOWNdb那一项也变红了。这就是救命的能力数据库一断监控立刻能感知。再启动 Prometheusdocker compose up -d prometheus打开http://localhost:9090在查询框输入http_server_requests_seconds_count就能看到请求数的实时变化。多次刷新你的订单接口曲线会涨——这就是服务状态好不好的可视化答案。3.8 自定义健康检查与指标真实项目里健康检查绝不只查数据库。比如某个关键的下游服务挂了你的服务也该报不健康。用 10 行代码就能加一个自定义检查器packagecom.example.monitor.health;importorg.springframework.boot.actuate.health.Health;importorg.springframework.boot.actuate.health.HealthIndicator;importorg.springframework.stereotype.Component;/** * 自定义健康检查模拟检查下游库存服务是否可达 */ComponentpublicclassStockServiceHealthIndicatorimplementsHealthIndicator{OverridepublicHealthhealth(){booleanreachablecheckStockService();if(reachable){returnHealth.up().withDetail(stock-service,reachable).build();}returnHealth.down().withDetail(stock-service,unreachable).build();}privatebooleancheckStockService(){// 真实项目里这里是 HTTP 调用库存服务探活或检查连接池// 这里用一个可配置的开关模拟方便演示returnBoolean.parseBoolean(System.getProperty(stock.up,true));}}这段代码的关键是实现了HealthIndicator接口的health()方法返回Health.up()或Health.down()。只要这个类被 Spring 扫描到它就会自动并入整体健康检查——你不需要改任何配置。启动后用-Dstock.upfalse运行健康检查立刻变 DOWN。业务指标也同理。比如你想监控订单今日成交量用一个计数器即可packagecom.example.monitor.metrics;importio.micrometer.core.instrument.Counter;importio.micrometer.core.instrument.MeterRegistry;importorg.springframework.stereotype.Component;ComponentpublicclassOrderMetrics{privatefinalCounterorderCounter;publicOrderMetrics(MeterRegistryregistry){// 注册一个计数器带一个标签 typenormal 方便按维度统计this.orderCounterCounter.builder(orders.created.total).tag(type,normal).description(累计创建的订单数).register(registry);}publicvoidrecordOrderCreated(){orderCounter.increment();}}Micrometer 的MeterRegistry会自动注入Counter.builder定义一个计数器你在业务代码里调用recordOrderCreated()就能累加。这个指标会出现在/actuator/prometheus里Prometheus 就能抓到、告警。四、踩坑经验和最佳实践监控这个领域坑特别多我直接给你讲我踩过的真实教训。坑一健康检查把show-details开成 always 后暴露了内部信息。默认show-details: never只返回整体 UP/DOWN很安全。但你想看详细组件就得开always这会泄露数据库类型、磁盘路径这类信息。生产环境建议用show-details: when-authorized并在 Spring Security 里限制只有内网/监控系统放行。我见过有人图省事直接always结果把内部拓扑暴露给了外网。坑二Actuator 端点暴露了但没有做权限保护。/actuator/env会把你所有的环境变量列出来包括数据库密码、第三方密钥很多团队只记得堵/actuator/prometheus忘了env、heapdump、logfile这些同样危险。最佳实践是默认只暴露 health 和 info其他端点按需开、加权限。坑三健康检查太重把应用拖垮。如果不做限制健康检查每次都会真实地去连数据库、查连接池。K8s 或负载均衡每 5 秒探一次连接风暴很快就把数据库打垮。解决方法是健康检查连接到独立的、轻量的探活连接池并且 8080 端口业务监控混用和 8081 端口只放监控分开让探针走独立的监控端口不影响业务。坑四只看整体状态忽略了OUT_OF_SERVICE。有些组件比如修复中的依赖不是 down 而是 out of service如果聚合器没配好整体状态可能仍是 UP导致流量没被摘掉。生产上要把StatusAggregator配成只要有一个关键组件 OUT_OF_SERVICE 就算整体不可用。坑五指标和日志对不上排查费劲。你看到指标异常却不知道对应哪条日志。最佳实践是给请求加上traceId/spanId让指标http.server.requests和日志互相串起来。这样告警来了你能顺着 traceId 快速定位到具体请求和报错。几个务必遵守的规范生产环境 Actuator 端口建议单独开放用management.server.port8081把监控和业务端口分开。management.endpoints.web.exposure.include精确到端点名永远别用*。打指标时合理用 tag 维度应用名、实例、接口路径但 tag 别太多——Prometheus 的维度是最宝贵的资源tag 爆炸会拖垮存储。告警规则要设持续时间比如连续 3 分钟才告警避免抖动误报把运维半夜吵醒。五、性能对比和技术选型Actuator 本身的开销可以忽略不计——健康检查一次只多几次轻量探测指标采集是异步的正常业务量下对吞吐的影响在 1% 以内。真正影响性能的是你暴露了多少指标、tag 有没有爆炸。所以核心矛盾永远是监控数据丰富度 vs 系统负载原则是只采集真正关心的指标。技术选型上常规建议是需求推荐方案说明单机/小团队快速上手Actuator 浏览器直接看/actuator/health零成本够用即可规模化采集可视化Actuator Prometheus GrafanaJava 后端事实标准Micrometer 原生支持需要告警通知加上 Alertmanager邮件/钉钉/企业微信Prometheus 官方配套云厂商托管各云 APM阿里云 ARMS 等贵但省运维自动埋点选型结论很明确中小团队直接用 Prometheus Grafana Actuator 这套开源组合性价比最高。Micrometer 把 Actuator 和 Prometheus 无缝打通你几乎不需要写任何对接代码——这也是我强烈推荐用micrometer-registry-prometheus而不自己手写监控上报的原因。等规模大到需要链路追踪、自动告警编排时再考虑引入 APM 也不迟。六、总结回到开头的灵魂三问服务还活着吗状态好不好什么时候开始变差Actuator Prometheus Grafana 这套组合把三件事全办了。核心要点回顾Actuator 通过 HTTP 端点暴露服务状态/actuator/health做健康检查/actuator/prometheus提供指标。Micrometer 是数据的统一管道让 Spring Boot 天然对接 Prometheus不需要自己写上报代码。自定义HealthIndicator可以检查任何你关心的下游依赖自定义Meter可以监控任何业务指标。健康检查 指标采集 告警规则三者配合才是完整的监控闭环——光有数据不告警等于没监控。生产安全第一端点精确暴露、监控独立端口、敏感端点加权限。你只需要照着上面的工程结构敲一遍就能拥有一个能上线的监控方案。遇到半夜服务出问题你手机里的告警会先醒而不是用户先打电话。监控做到位运维才能睡个安稳觉——这才是它真正的价值。