news 2026/8/8 10:43:18

AI多Agent协作系统实战(二十五):Spring Boot静态资源同步:为什么你改了代码但线上还是旧的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI多Agent协作系统实战(二十五):Spring Boot静态资源同步:为什么你改了代码但线上还是旧的?

系列第25篇 | 三个真实案例告诉你:改src≠改target,Spring Boot不背这个锅

背景

“我明明改了那个CSS文件,刷新页面怎么还是旧的?”

这句话,我在最近一周内说了至少三次。每次都是信心满满地改完代码 → 刷新页面 → 看到旧内容 → 一脸懵 → 发现忘了mvn package

这是一个所有Spring Boot开发者都会遇到的问题,但当我们把它放进AI Agent自动开发流程中时,这个问题被放大了——Agent改完src/main/resources/static/下的文件后,理所当然地认为"改完了",但实际上浏览器加载的仍然是旧的classpath资源。

案例一:改了3个页面的CSS,线上纹丝不动

某次任务需要修改user.htmlrole.htmlpermission.html三个页面的样式。开发者(无论是人还是AI)修改了src/main/resources/static/下的源文件,然后自信满满地刷新了http://localhost:8080/user.html——结果页面一点变化都没有。

为什么?

Spring Boot在开发模式下,静态资源的加载路径和大多数人想的不一样。当你的项目结构是:

gainch-service/ ├── src/main/resources/static/ │ ├── user.html │ └── css/ └── target/classes/ └── static/ ├── user.html └── css/

运行时,Spring Boot读取的是**target/classes/static/**,而不是你刚刚修改的src/main/resources/static/。这两个目录在mvn packagemvn compile时会同步一次,但在这之后,你对src做的任何修改都不会自动同步到target。

案例二:Agent打包部署的跳步问题

在我们的AI Agent自动开发流程中,小虾(开发Agent)完成代码修改后,需要执行deploy.sh来打包部署:

#!/bin/bashcd/vol1/1000/workspace/file/8080/gainch-service mvn clean package-DskipTests-qjava-jartarget/gainch-service-1.0.0.jar&

这个脚本做了两件事:

  1. mvn clean package——重新编译、打包,把src/的内容同步到target/
  2. java -jar——用新JAR包启动服务

有一次,小虾修改完代码后跳过了部署步骤,直接在回复中说"开发完成"。review.py检查时发现src/下的文件确实修改了(文件mtime更新了),但线上访问页面仍然是旧的——因为target/classes/里的还是旧文件。

这个问题被review.py的mtime检查捕获到,但因为review.py检查的是src/main/resources/static/下的文件mtime,而不是target/classes/的,所以误判为"修改已生效"。

案例三:target/classes残留导致的幽灵修改

还有一个更隐蔽的问题:当你修改了src/下的文件,然后手动静止了Java进程,用java -jar重新启动(跳过mvn package),这时Spring Boot会直接使用target/classes/中的旧文件

为什么?因为java -jar target/gainch-service-1.0.0.jar加载的是JAR包内的classpath资源,而JAR包是在上次mvn package时构建的。如果你只重启JVM而不重新打包,JAR包里的静态资源文件永远是老的。

有一次我连续改了三次CSS,每次都重启了Java进程,但页面始终没变。排查了十分钟才发现:上次mvn package失败(测试没通过),target/gainch-service-1.0.0.jar是更早之前的版本。我一直在用旧JAR包重启,改再多src文件也没用。

根因分析:Spring Boot的classpath机制

Spring Boot的静态资源加载路径是这样的:

请求 /user.html ↓ Spring DispatcherServlet ↓ ResourceHttpRequestHandler ↓ classpath:/static/ (即 target/classes/static/) ↓ 返回 target/classes/static/user.html

关键点:src/main/resources/是源文件目录,target/classes/是编译输出目录。Spring Boot运行时只认target,不认src。

mvn package / mvn compile ↓ src/main/resources/ ────────────→ target/classes/ (源文件) 同步 (运行时加载)

这不是Bug,是Spring Boot的标准设计。只有当你开启了spring-boot-devtools的LiveReload或者使用了spring.thymeleaf.cache=false(针对模板引擎)时,才会在开发模式下热加载静态资源。但对于生产部署或java -jar方式运行,必须重新打包。

经验总结

  1. 改了静态文件后必须mvn package,只重启JVM是不够的
  2. 部署脚本是最后一道防线deploy.sh中的mvn clean package -DskipTests不能跳步
  3. 检查target/classes的时间戳:如果target比src旧,说明部署还没生效
  4. devtools只适合本地开发,对于容器化或生产环境部署,必须走完整打包流程
  5. review.py应该检查target/classes/的文件mtime,而不是只检查src/下的(这也是我们正在修复的)

三个案例有一个共同点:我们把"改了文件"等同于"生效了",但实际上改了文件只是第一步,部署才是让修改真正生效的那一步。就像你换了房间的门锁,但你的钥匙还是旧的——你需要把新钥匙配好、交到每个人手上,才算真正换了锁。

欢迎加入QQ频道共同交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/8 10:43:14

嵌入式燃气灶选购指南:从5.2kW火力到安装维护全解析

1. 先搞清楚“5.2kW猛火”到底意味着什么如果你正在看嵌入式燃气灶,大概率会看到“5.0kW”、“5.2kW”这类火力参数。很多人第一反应是“数字越大火力越猛”,这没错,但更关键的是要明白,这个“猛火”到底能不能在你的厨房里发挥出…

作者头像 李华
网站建设 2026/8/8 10:43:10

绝地求生压枪脚本终极指南:5分钟掌握罗技鼠标宏后坐力控制

绝地求生压枪脚本终极指南:5分钟掌握罗技鼠标宏后坐力控制 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 想要在PUBG中实现稳定压枪…

作者头像 李华
网站建设 2026/8/8 10:43:09

终极指南:3分钟免费生成Beyond Compare 5永久密钥的Python工具

终极指南:3分钟免费生成Beyond Compare 5永久密钥的Python工具 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否正在为Beyond Compare 5的30天评估期到期而烦恼?这款…

作者头像 李华
网站建设 2026/8/8 10:43:07

【MYSQL】MYSQL学习的一大重点:视图

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立…

作者头像 李华
网站建设 2026/8/8 10:42:39

UPI钱包协议解析与交易流水获取技术实现

1. UPI钱包协议的核心机制解析 印度统一支付接口(UPI)作为全球实时支付系统的典范,其技术架构设计极具参考价值。UPI协议栈采用分层设计,从下至上依次为: 底层银行账户层:通过虚拟支付地址(VPA)映射实际银行账户 核心交易层&…

作者头像 李华
网站建设 2026/8/8 10:41:16

解决OpenClaw访问localhost报错1008的完整指南

1. OpenClaw访问localhost报错1008问题解析最近在本地部署OpenClaw时遇到了一个典型问题:通过OpenClaw访问localhost:18789端口时返回1008错误。这个错误在开发者社区和各大技术论坛上讨论度很高,特别是随着本地AI开发环境的普及,类似问题频繁…

作者头像 李华