问题现场
一个标准的多模块项目:
BaseLearn/
├── pom.xml # 父 POM
├── base-api/ # API 模块:定义接口和 DTO
│ └── pom.xml
└── base-server/ # Server 模块:引用 base-api
└── pom.xml
IDE 里一切正常,Ctrl + 点击能跳转。但一到打包:
[ERROR] 程序包 com.cheems.baseapi.xxxx 不存在
[ERROR] 找不到符号
排查轨迹
第一反应:构建顺序问题
mvn clean install -pl base-api # 先装 api
mvn clean install -pl base-server # 再装 server
不行。
第二反应:父 POM 的 modules 顺序
<modules>
<module>base-api</module> <!-- 确保先构建 -->
<module>base-server</module>
</modules>
不行。
第三反应:IDEA 缓存
Invalidate Caches + 重新导入 Maven。不行。
第四反应:开始怀疑插件
查看 base-api 的 pom.xml,发现了问题:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
根因分析
Maven 默认打包 vs Spring Boot 打包
Maven 默认 jar:
┌──────────────────────┐
│ com.cheems.baseapi │ ← 可以 import + 类路径引用
│ (你的 .class 文件) │
└──────────────────────┘
Spring Boot 打包:
┌──────────────────────┐
│ BOOT-INF/classes/ │ ← 你的类被塞进去了
│ ├── com/cheems/... │
│ └── ... │
│ META-INF/ │
│ org/springframework/│
└──────────────────────┘
spring-boot-maven-plugin 会重新打包(repackage),将模块变成一个可执行的 fat jar。jar 的内部结构被改写——类文件不再在根目录,而是被放到 BOOT-INF/classes/ 下面。
其他模块尝试引用这个 jar 时,类加载器在根路径找不到类,因为它们在 BOOT-INF 里面。
这就是为什么 IDEA 能索引到(IDEA 看的是源码/编译输出,不是最终 jar),但 Maven 打包时找不到。
哪些模块需要这个插件?
可执行模块(需要 spring-boot-maven-plugin):
└── base-server(入口类在这里,要打成可执行 jar)
被依赖模块(不需要):
├── base-api(被 server 引用 → 普通 jar 即可)
├── base-common
└── base-domain
原则:只有包含 main 方法、需要独立运行的那个模块才需要 spring-boot-maven-plugin。
两种修复
方案一:删掉 API 模块中的插件
<!-- base-api/pom.xml → 删除整个 plugins 块 -->
最适合开头那个例子——api 模块不需要独立运行。
方案二:跳过 repackage
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
适合用 spring-boot-starter-parent 的继承场景,子模块不想 repackage 但也不想删插件声明。
方案三:用 classifier 区分
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
这样会同时产出两个 jar:
base-api.jar(普通 jar,可被引用)base-api-exec.jar(可执行 jar)
总结
spring-boot-maven-plugin改变了 jar 内部结构(BOOT-INF 格式)- 被其他模块引用的模块不能用这个插件 repackage
- 只有入口模块(有 main 的)才需要
- Maven 构建顺序和 IDE 缓存排查是常规操作,但深层问题往往是打包配置
☕ 如果这篇文章对你有帮助
欢迎请我喝杯咖啡支持一下
评论