AI多Agent实战(25) Spring Boot静态资源同步:代码更新后线上还是旧?

作者:技术拾光

时间:2026-07-31

浏览:339

SpringBoot静态资源从target/classes加载,修改后需执行mvnpackage同步。AIAgent开发中跳过部署或仅重启JVM会导致旧资源生效,需确保完整打包流程。检查target时间戳可验证部署是否生效。

文章目录

背景

“我明明改了那个CSS文件,刷新页面怎么还是旧的?”——这是Spring Boot静态资源同步中最常见的问题之一。

AI多Agent实战(25) Spring Boot静态资源同步:代码更新后线上还是旧?

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

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

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

某次任务需要修改user.html、role.html、permission.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 package或mvn compile时会同步一次,但在这之后,你对src做的任何修改都不会自动同步到target。

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

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

#!/bin/bash
cd /vol1/1000/workspace/file/8080/gainch-service
mvn clean package -DskipTests -q
java -jar target/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/下的(这也是我们正在修复的)

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章