Spring Boot Actuator监控实战:从端点数据到可视化驾驶舱
1. 项目概述:从“黑盒”到“白盒”的运维跃迁
在微服务架构大行其道的今天,一个应用的健康状况、性能指标、内部状态,对于开发和运维团队来说,就像是飞机的仪表盘。如果仪表盘一片漆黑,你根本不知道飞机是在平稳飞行还是即将失速。Spring Boot Actuator 就是为你的应用装上这套“仪表盘”的标准组件,而 Monitor 则是将这些仪表数据以更直观、更友好的方式呈现出来的“驾驶舱”界面。很多开发者知道 Actuator 能提供/health、/metrics端点,但往往止步于命令行里curl一下,或者看一堆 JSON 数据。这就像你拿到了飞机的所有传感器原始数据流,却要自己心算油量和航速,效率低下且容易出错。
这个项目的核心,就是深度挖掘 Spring Boot 自带的 Actuator 监视器的全部潜力,并搭建一个专属的、可视化的监控页面(Monitor),将那些冰冷的 JSON 端点数据,转化为一目了然的图表、仪表盘和告警信息。它解决的不仅仅是“有没有监控”的问题,更是“监控好不好用、能不能快速发现问题”的效率问题。无论你是独立开发者,还是中小团队的负责人,一个轻量级、零成本(指无需引入 Grafana、Prometheus 等重型外部系统)的内置可视化监控方案,都能让你在应用上线初期或日常维护中,获得远超预期的掌控感。接下来,我将带你从原理到实践,一步步构建并优化这个属于你自己的监控驾驶舱。
2. 核心组件深度解析:Actuator 的里里外外
2.1 Actuator 端点:你的应用数据“矿藏”
Spring Boot Actuator 的本质,是通过一系列 HTTP 或 JMX 端点(Endpoints)暴露应用的内部信息。你可以把它们理解成一个个标准化的数据“矿洞”,每个矿洞产出特定类型的“矿石”(数据)。
核心端点分类与用途:
健康检查端点 (
/actuator/health): 这是最常用的端点。它不仅仅返回一个简单的 “UP” 或 “DOWN”。在引入相关依赖后,它可以提供组件级健康状态,例如:db: 数据库连接状态。diskSpace: 磁盘空间状态。redis: Redis 连接状态。mail: 邮件服务器状态。 其底层基于HealthIndicator接口实现,你可以轻松地自定义健康检查逻辑。
指标度量端点 (
/actuator/metrics): 这是性能监控的宝库。它集成了 Micrometer 度量门面,可以暴露海量指标,如:jvm.memory.used: JVM 内存使用量。http.server.requests: HTTP 请求计数、耗时、状态码分布。system.cpu.usage: 系统 CPU 使用率。tomcat.sessions.active.current: Tomcat 活跃会话数。 这些指标是绘制性能趋势图的基础数据源。
信息端点 (
/actuator/info): 用于暴露任意的应用信息,如版本号、构建信息、Git 提交信息等。通常通过application.properties或编程方式注入。环境端点 (
/actuator/env): 展示当前应用所有可用的配置属性及其来源(命令行、配置文件、默认值等)。排查配置问题时极其有用。日志级别端点 (
/actuator/loggers): 允许在运行时动态查看和修改应用程序中各个 Logger 的日志级别。无需重启即可临时开启 DEBUG 日志进行问题追踪。线程转储端点 (
/actuator/threaddump): 获取当前 JVM 所有线程的快照,用于分析死锁、线程阻塞等问题。映射端点 (
/actuator/mappings): 展示所有@RequestMapping路径的映射关系,是梳理 API 接口的利器。
配置要点与安全考量:默认情况下,出于安全考虑,只有/health和/info端点是通过 HTTP 暴露的。要启用更多端点,需要在application.properties中配置:
# 暴露所有Web端点(不包括shutdown) management.endpoints.web.exposure.include=* # 或者指定需要暴露的端点 management.endpoints.web.exposure.include=health,info,metrics,env,loggers # 通常不暴露shutdown端点,除非有严格管控 management.endpoints.web.exposure.exclude=shutdown # 自定义端点访问路径前缀,避免与业务接口冲突 management.endpoints.web.base-path=/manage # 此时健康检查端点变为 /manage/health重要安全提示:在生产环境中,绝对不要不加保护地暴露所有端点(尤其是
env,heapdump,shutdown)。务必结合 Spring Security 对/actuator路径进行访问控制,例如只允许内网IP或拥有特定角色的用户访问。
2.2 可视化页面的必要性:数据与洞察之间的桥梁
原始端点数据(JSON格式)对于程序调用是友好的,但对于人类来说并不直观。想象一下,你需要评估过去一小时的系统负载,是愿意看一个包含了100个时间戳和CPU使用率数值的JSON数组,还是愿意看一条平滑的折线图?答案显而易见。
一个可视化监控页面(Monitor)的价值在于:
- 降低认知负荷:将数字转化为图形,大脑能更快识别模式、趋势和异常点。
- 实时性:自动刷新的仪表盘提供了近乎实时的系统状态感知。
- 聚合与关联:可以在一个页面上并排显示CPU、内存、请求量、错误率,便于关联分析。例如,发现内存使用率飙升的同时,请求延迟也增加了,这可能指向内存泄漏或GC问题。
- 历史趋势:图表能直观展示指标随时间的变化,这对于容量规划、性能优化效果评估至关重要。
- 告警预览:虽然完整的告警需要集成其他系统,但可视化页面可以高亮显示当前已接近阈值的指标(如磁盘使用率>85%),起到预警作用。
因此,我们的目标不是替代专业的 APM(应用性能管理)系统,而是在 Spring Boot 生态内,以最小成本和最快速度,搭建一个功能全面、满足日常开发和预生产环境监控需求的“轻量级驾驶舱”。
3. 构建可视化监控页面的三种实践路径
3.1 方案一:使用现成的开源管理界面(Spring Boot Admin)
这是最快速、最成熟的方案。Spring Boot Admin (SBA) 是一个社区活跃的开源项目,它专门为 Spring Boot Actuator 端点提供了一个功能强大的管理界面。
实现步骤:
创建 Admin Server(监控服务器): 这是一个独立的 Spring Boot 应用,负责收集和展示被监控客户端的信息。
<!-- 在 admin-server 项目的 pom.xml 中 --> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> <version>2.7.10</version> <!-- 请使用与Spring Boot版本兼容的最新版 --> </dependency>// 启动类 @SpringBootApplication @EnableAdminServer public class AdminServerApplication { public static void main(String[] args) { SpringApplication.run(AdminServerApplication.class, args); } }配置
application.properties,设置端口(如 8081)。配置 Client(被监控的应用): 在你的业务应用(即需要被监控的应用)中,添加客户端依赖并配置 Admin Server 地址。
<dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> <version>2.7.10</version> </dependency># 业务应用的配置 spring.boot.admin.client.url=http://localhost:8081 # Admin Server地址 spring.boot.admin.client.instance.name=我的生产服务 management.endpoints.web.exposure.include=* # 暴露端点给SBA访问与使用: 启动 Admin Server 和 Client 应用,访问
http://localhost:8081。你将看到一个功能齐全的监控界面,包括:- 应用墙:所有注册应用的概览和状态。
- 详情仪表盘:点击单个应用,进入其专属面板,包含健康状态、JVM内存/线程指标、环境变量、日志级别管理、线程转储下载等。
- 实时图表:对 Metrics 数据进行可视化展示。
- 告警通知:可集成邮件、Slack等,在应用状态变更时发送通知。
实操心得:
- SBA 的客户端会自动向服务器注册,并定期发送心跳。确保网络连通,且客户端配置的
spring.boot.admin.client.url正确。 - 生产环境务必为 SBA Server 配置安全认证(如集成 Spring Security),防止未授权访问。
- SBA 本身也是一个 Spring Boot 应用,可以集群化部署以实现高可用。
3.2 方案二:自定义集成前端图表库(如 ECharts)
如果你需要更定制化的界面,或者希望将监控面板嵌入到自己的内部管理系统中,那么自己动手构建前端页面是更灵活的选择。这里我们使用流行的 ECharts 库。
实现步骤:
后端准备(提供数据API): 首先,确保 Actuator 端点已暴露。然后,你可以选择直接代理 Actuator 端点,或者创建更定制化的 Controller 来聚合、转换数据。
@RestController @RequestMapping("/api/monitor") public class MonitorController { @Autowired private MeterRegistry meterRegistry; // 示例:获取JVM堆内存使用情况 @GetMapping("/jvm/heap-memory") public Map<String, Object> getJvmHeapMemory() { Map<String, Object> result = new HashMap<>(); // 通过MeterRegistry查询指标 Meter usedMeter = meterRegistry.find("jvm.memory.used").tag("area", "heap").meter(); Meter maxMeter = meterRegistry.find("jvm.memory.max").tag("area", "heap").meter(); // ... 获取测量值并计算使用率 ... // 实际项目中需要处理数据采集和聚合的逻辑 result.put("used", used); result.put("max", max); result.put("usagePercentage", (used / max) * 100); result.put("timestamp", System.currentTimeMillis()); return result; } // 示例:获取最近HTTP请求统计 @GetMapping("/http/requests") public List<Map<String, Object>> getHttpRequestMetrics() { // 查询 http.server.requests 指标,按URI、状态码等维度聚合 // 返回结构化的数据供前端图表使用 return ...; } }更简单的做法是,直接提供一个接口返回
/actuator/metrics中特定指标的数据,让前端解析。前端页面开发: 创建一个 HTML 页面,引入 ECharts 和 axios(用于请求API)。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>服务监控面板</title> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <style> .chart-panel { width: 48%; height: 400px; display: inline-block; margin: 1%; } </style> </head> <body> <h2>服务实时监控</h2> <div id="heapMemoryChart" class="chart-panel"></div> <div id="cpuChart" class="chart-panel"></div> <div id="httpRequestChart" class="chart-panel"></div> <!-- 更多图表容器 --> <script> // 初始化图表 const heapMemoryChart = echarts.init(document.getElementById('heapMemoryChart')); const cpuChart = echarts.init(document.getElementById('cpuChart')); // ... 初始化其他图表 // 定义图表配置 const heapMemoryOption = { title: { text: 'JVM堆内存使用率' }, tooltip: { formatter: '{b}<br/>{a}: {c}%' }, series: [{ name: '使用率', type: 'gauge', detail: { formatter: '{value}%' }, data: [{ value: 50, name: '使用率' }] // 初始值 }] }; heapMemoryChart.setOption(heapMemoryOption); // 定时从后端API获取数据并更新图表 function fetchDataAndUpdate() { axios.get('/api/monitor/jvm/heap-memory').then(response => { const data = response.data; heapMemoryChart.setOption({ series: [{ data: [{ value: data.usagePercentage.toFixed(2) }] }] }); }); // 获取其他指标数据... } // 每5秒更新一次 setInterval(fetchDataAndUpdate, 5000); fetchDataAndUpdate(); // 立即执行一次 </script> </body> </html>
注意事项:
- 这种方案需要你具备一定的前后端开发能力。
- 对于时间序列数据(如过去一小时的CPU趋势),后端需要有能力存储或聚合历史数据。Actuator 默认只提供当前瞬时值或近期快照,长期历史存储通常需要集成 Micrometer 到时序数据库(如 Prometheus, InfluxDB)。
- 前端页面的安全也需考虑,避免被公开访问。
3.3 方案三:轻量级第三方工具集成(如 Prometheus + Grafana)
当你的监控需求超越单个应用,需要集群监控、长期历史数据存储、强大的告警能力和极其灵活的仪表盘时,Prometheus + Grafana 组合是业界事实上的标准。Spring Boot Actuator 通过micrometer-registry-prometheus可以无缝对接。
实现步骤:
引入依赖:
<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>暴露 Prometheus 端点:
management.endpoints.web.exposure.include=health,info,prometheus此时,访问
/actuator/prometheus会返回 Prometheus 可以直接抓取的 metrics 格式数据。部署与配置 Prometheus: 下载 Prometheus,编写配置文件
prometheus.yml,添加你的应用作为抓取目标。scrape_configs: - job_name: 'spring-boot-app' metrics_path: '/actuator/prometheus' static_configs: - targets: ['your-app-host:8080'] # 你的应用地址 labels: application: 'my-springboot-service'部署与配置 Grafana: 下载 Grafana,添加 Prometheus 作为数据源。然后从 Grafana 官方社区导入丰富的 Spring Boot / JVM 监控仪表盘模板(如 ID 为 4701 的 “JVM Micrometer” 仪表盘)。
方案对比与选型建议:
| 特性 | Spring Boot Admin | 自定义前端 (ECharts) | Prometheus + Grafana |
|---|---|---|---|
| 上手速度 | 极快,几乎零配置 | 中等,需前后端开发 | 中等,需部署中间件 |
| 定制化程度 | 中等,界面固定但功能全 | 极高,完全自主控制 | 高,Grafana面板可高度定制 |
| 历史数据与趋势 | 有限,主要看当前/近期 | 依赖后端实现,较复杂 | 极强,专为时序数据设计 |
| 告警能力 | 基础(状态变更) | 需自行实现 | 强大且灵活 |
| 多应用/集群监控 | 支持,是核心功能 | 需自行设计聚合 | 原生支持,是标准方案 |
| 生产环境适用性 | 适合中小规模,内部监控 | 适合特定嵌入式场景 | 适合大规模,生产级 |
| 学习/维护成本 | 低 | 中到高 | 中(需学习PromQL) |
个人建议:对于快速启动、内部项目或监控需求不那么复杂的场景,Spring Boot Admin 是最佳选择。当监控成为基础设施的一部分,且需要长期、大规模、专业化运维时,Prometheus + Grafana 是必然的演进方向。自定义前端方案则适用于有特殊UI集成需求或作为学习练手的场景。
4. 高级特性与生产级优化实战
4.1 自定义健康指示器与业务健康检查
Actuator 的/health端点之所以强大,在于其可扩展性。你可以为任何关键业务组件创建自定义的HealthIndicator。
场景示例:监控一个关键的第三方API接口是否可用。
@Component public class ThirdPartyApiHealthIndicator implements HealthIndicator { @Autowired private ThirdPartyApiClient apiClient; @Override public Health health() { // 执行一个轻量级的检查,例如调用一个状态接口 try { ApiStatus status = apiClient.getStatus(); if ("OK".equals(status.getCode())) { return Health.up() .withDetail("service", "ThirdPartyAPI") .withDetail("responseTime", status.getResponseTime() + "ms") .build(); } else { return Health.down() .withDetail("service", "ThirdPartyAPI") .withDetail("error", status.getMessage()) .build(); } } catch (Exception e) { return Health.down(e) .withDetail("service", "ThirdPartyAPI") .build(); } } }添加后,你的/health端点 JSON 响应中就会包含一个thirdPartyApi组件状态。在 Spring Boot Admin 或自定义页面中,这个组件的状态会清晰显示。
生产级技巧:
- 超时控制:健康检查必须快速,务必设置合理的超时时间(如 3-5 秒),避免因第三方服务缓慢拖慢整个健康检查。
- 缓存结果:对于检查成本较高的操作,可以考虑缓存健康状态几秒钟,避免每次调用
/health都触发真实检查。但缓存时间不宜过长,以免失去实时性。 - 分级检查:可以定义
Liveness(存活)和Readiness(就绪)两种健康状态。Kubernetes 等平台会使用它们。Spring Boot 通过management.endpoint.health.group配置支持。
4.2 自定义度量和业务指标打点
除了系统指标,打点业务指标是监控业务逻辑的关键。Micrometer 提供了强大的 API。
场景示例:监控订单创建的成功率和耗时。
@Service public class OrderService { // 计数器:用于统计次数 private final Counter orderCreateCounter; // 计时器:用于统计耗时 private final Timer orderCreateTimer; public OrderService(MeterRegistry registry) { // 初始化计数器,可以添加标签(维度)以便细分统计 this.orderCreateCounter = Counter.builder("order.create.total") .description("Total number of orders created") .tag("type", "online") // 可以按类型、渠道等打标签 .register(registry); // 初始化计时器 this.orderCreateTimer = Timer.builder("order.create.time") .description("Time taken to create an order") .register(registry); } public Order createOrder(OrderRequest request) { // 使用 Timer.Sample 记录耗时 Timer.Sample sample = Timer.start(); Order order = null; try { // 业务逻辑... order = doCreateOrder(request); orderCreateCounter.increment(); // 成功时计数 return order; } catch (Exception e) { // 可以定义另一个标签为“status=failure”的计数器来统计失败 Counter.builder("order.create.total") .tag("status", "failure") .register(meterRegistry) .increment(); throw e; } finally { // 无论成功失败,都记录耗时 sample.stop(orderCreateTimer); } } }这样,在metrics端点或 Prometheus 中,你就能看到order_create_total(订单创建总数)和order_create_time_seconds(创建耗时分布,包括直方图、百分位数等)这两个自定义业务指标。
4.3 监控数据的安全、权限与审计
将监控端点暴露在公网是极其危险的。必须实施安全措施。
集成 Spring Security:
@Configuration public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/actuator/health", "/actuator/info").permitAll() // 健康检查通常允许公开 .antMatchers("/actuator/**").hasRole("ADMIN") // 其他端点需要ADMIN角色 .anyRequest().authenticated() // 其他业务接口按需配置 .and() .httpBasic(); // 使用HTTP Basic认证,生产环境建议用更安全的如JWT } }网络层隔离:通过防火墙或安全组策略,限制只有监控服务器(如 Prometheus, SBA Server)或内部管理网络的IP可以访问应用的 Actuator 端点。
敏感信息脱敏:
/env端点会暴露所有配置,包括密码。务必使用******对敏感值进行脱敏。Spring Boot 会自动对属性名包含password,secret,key,token等关键词的配置进行脱敏。你也可以自定义SanitizingFunction。
4.4 性能开销考量与最佳实践
开启 Actuator 和监控必然带来少量性能开销,但通过合理配置可以将其降至最低。
- 端点暴露选择:只暴露必要的端点。例如,生产环境可以不暴露
heapdump(生成堆转储非常耗资源)或频繁调用的端点。 - 指标采集频率:对于集成 Prometheus 的场景,调整 Prometheus 的
scrape_interval(抓取间隔,如 30s)。过于频繁(如 1s)会给应用带来不必要的压力。 - 度量注册表选择:Micrometer 支持多种注册表(Prometheus, InfluxDB, Atlas等)。确保只引入你实际使用的那个。例如,只用 Prometheus 就只引入
micrometer-registry-prometheus,避免加载其他无用的模块。 - 自定义指标的精简:自定义业务指标时,避免使用过多的高基数标签(Tag)。例如,不要把用户ID作为标签,这会导致指标数量爆炸,严重影响监控系统性能。标签应使用有限枚举值,如渠道、地区、状态等。
5. 常见问题排查与调试技巧实录
即使按照指南操作,在实际部署中也可能遇到各种问题。这里记录几个我踩过的坑和解决方法。
问题1:Spring Boot Admin Client 无法在 Server 上注册,列表为空。
排查步骤:
- 检查网络与地址:确认 Client 应用的
spring.boot.admin.client.url配置的地址和端口号完全正确,并且从 Client 所在机器能访问到该地址(telnet admin-server-host port)。 - 检查端点暴露:确认 Client 应用的
management.endpoints.web.exposure.include包含了*或至少包含了health,info,metrics,env等关键端点。 - 查看 Client 日志:在 Client 应用启动日志中搜索 “Registration” 或 “Failed to register”。通常会打印详细的错误信息,如连接超时、认证失败等。
- 查看 Server 日志:在 Admin Server 日志中查看是否有注册请求到达。
- 检查实例 ID:默认情况下,实例 ID 由
spring.application.name和随机值生成。如果多个实例名称相同,可能会覆盖。可以显式设置spring.boot.admin.client.instance.service-base-url或management.server.port来确保唯一性。
- 检查网络与地址:确认 Client 应用的
根本原因与解决:最常见的原因是安全配置冲突。如果 Client 应用也配置了 Spring Security,可能会拦截掉向
/instances端点发送的注册请求。需要在 Client 的安全配置中,将 Admin Server 的注册路径(通常是/instances)和 Actuator 端点路径排除在外。// 在Client的安全配置中 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/actuator/**", "/instances/**").permitAll() // 允许Admin Server访问 ... // 其他配置 }
问题2:/actuator/prometheus端点返回 404。
排查步骤:
- 确认依赖:检查
pom.xml或build.gradle中是否引入了micrometer-registry-prometheus依赖。 - 确认配置:检查
management.endpoints.web.exposure.include是否包含了prometheus。 - 检查依赖冲突:有时其他依赖(特别是老版本的监控相关依赖)可能会干扰。使用
mvn dependency:tree或./gradlew dependencies查看依赖树,确保 Micrometer 和 Prometheus registry 的版本与 Spring Boot 兼容。
- 确认依赖:检查
解决:确保依赖和配置正确后,重启应用。访问
/actuator端点,查看暴露的端点列表中是否包含prometheus的链接。
问题3:自定义的健康检查 (HealthIndicator) 导致/health端点响应缓慢。
- 现象:调用
/health端点需要好几秒才返回。 - 排查:检查所有
HealthIndicator实现,特别是自定义的。在健康检查方法中加入日志,打印开始和结束时间。 - 解决:
- 优化检查逻辑:将同步 HTTP 调用改为带超时的异步调用,或使用缓存的结果。
- 使用健康检查组:Spring Boot 2.3+ 支持将健康检查分组。你可以为不同的检查设置不同的超时和缓存策略。
management.endpoint.health.group.readiness.include=db,diskSpace,myCustomCheck management.endpoint.health.group.readiness.additional-path=server:/ready - 分离检查:将耗时且非核心的检查移出
health端点,放到一个单独的readiness或liveness端点中。
问题4:Grafana 中看不到 Spring Boot 应用的指标数据。
- 排查步骤:
- 检查 Prometheus 目标状态:访问 Prometheus 的 Web UI (
http://prometheus-host:9090/targets),查看你的 Spring Boot 应用对应的 Job 状态是否为 “UP”。如果是 “DOWN”,鼠标悬停查看错误信息。 - 检查抓取地址:确认 Prometheus 配置中
targets的地址和端口是否正确,并且/actuator/prometheus路径可访问。 - 在 Prometheus 中验证数据:在 Prometheus UI 的 Graph 页面,输入一个简单的 PromQL 查询,如
up{job="spring-boot-app"},看是否有数据。或者直接查询jvm_memory_used_bytes等指标。 - 检查 Grafana 数据源:在 Grafana 中,测试配置的 Prometheus 数据源连接是否成功。
- 检查仪表盘变量:如果导入的仪表盘使用了变量(如
instance,job),确保这些变量与你 Prometheus 中的标签匹配,或者在 Grafana 面板的下拉框中选择了正确的值。
- 检查 Prometheus 目标状态:访问 Prometheus 的 Web UI (
问题5:监控数据量巨大,导致内存占用高或 Prometheus 存储压力大。
- 策略:
- 削减指标:通过
management.metrics.enable配置禁用不需要的指标。例如,management.metrics.enable.jvm=false禁用所有 JVM 指标(慎用)。 - 限制标签:如前所述,避免在自定义指标中使用高基数标签。
- 调整 Prometheus 抓取间隔:适当降低抓取频率。
- 使用 Prometheus 的远程写入:将数据写入到可扩展的远程存储中,如 Thanos、Cortex 或云厂商的托管服务。
- 定期清理:配置 Prometheus 的数据保留策略。
- 削减指标:通过
构建一个稳定、有用的监控体系不是一蹴而就的。我的经验是,从最简单的 Spring Boot Admin 开始,让它先跑起来,获得最基本的可见性。随着业务复杂度和团队需求的增长,再逐步引入 Prometheus 和 Grafana 来处理更复杂的指标、历史和告警。在这个过程中,不断审视你的监控指标是否真正反映了系统的健康度和业务的核心流程,避免为了监控而监控,让每一个图表和警报都有其明确的行动价值。最终,这套监控体系会成为你保障系统稳定、快速定位问题的“眼睛”和“耳朵”,其价值会远超最初的投入。
