一、开篇:这种项目为什么让人头大
和教科书上的"父子 pom"多模块项目不同,实际企业中的多模块项目往往是:
- 模块 A 是一个 Git 仓库,模块 B 是另一个 Git 仓库,互不相干
- 模块 A 的
pom.xml里写了<dependency>引用模块 B,但本地根本没有 B 的代码 - 本地编译报
Could not resolve dependencies: Could not find artifact com.xxx:module-b:jar:1.0.0 - 每个仓库有自己的
.gitignore、自己的README,有的甚至连 README 都没有 - 不同模块可能用不同版本的 Spring Boot、不同版本的 JDK
别慌。核心问题就两个:搞清模块间的依赖关系 、把依赖的模块安装到本地。
二、第一步:搞清楚有哪些模块,谁依赖谁
2.1 列出所有仓库
bash
# 假设你把所有模块都 clone 到 ~/projects/ 下
mkdir -p ~/projects/my-project
cd ~/projects/my-project
# 逐个 clone
git clone git@github.com:org/module-common.git
git clone git@github.com:org/module-dao.git
git clone git@github.com:org/module-service.git
git clone git@github.com:org/module-web.git
2.2 分析依赖关系
每个模块的 pom.xml 里,找到 <dependencies> 区域,关注 groupId 为你们公司自己的依赖:
xml
<!-- module-web/pom.xml -->
<dependencies>
<!-- 这是你们自己的模块 -->
<dependency>
<groupId>com.yourcompany</groupId>
<artifactId>module-service</artifactId>
<version>1.2.0</version>
</dependency>
<!-- 这是第三方依赖,暂时不用管 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
快速排查脚本(在项目根目录下执行):
bash
# 在所有仓库中搜索你们公司的 groupId,快速画出依赖图
grep -r "com.yourcompany" --include="pom.xml" . | \
grep "<artifactId>" | \
awk -F'/' '{print $2}' | \
sort -u
用一张纸画出来:
arduino
module-web → module-service → module-dao → module-common
2.3 用 Maven 命令看完整依赖树
进入任意一个模块目录:
bash
cd module-web
mvn dependency:tree -Dverbose > dependency-tree.txt
在输出中搜索 com.yourcompany,只关注你们自己的模块依赖。
三、第二步:正确导入到 IDEA
3.1 把所有模块放进同一个 IDEA 项目
这是最关键的一步。不要每个模块单独开一个 IDEA 窗口。
- File → New → Project from Existing Sources...
- 选择一个空的目录(比如
~/projects/my-project/) - File → Project Structure → Modules
- 点击 + → Import Module
- 逐个选择每个模块的
pom.xml,点击 Import as Maven project - 全部导入完成后,你的 IDEA 左侧 Project 视图应该是这样的:
arduino
my-project/
├── module-common (Maven)
├── module-dao (Maven)
├── module-service (Maven)
└── module-web (Maven)
3.2 确认 JDK 版本统一
- File → Project Structure → Project
- Project SDK 选择 1.8
- Project language level 选择 8
- File → Settings → Build, Execution, Deployment → Compiler → Java Compiler
- 确认每个模块的 Target bytecode version 都是 1.8
四、第三步:解决编译依赖(最核心的一步)
4.1 问题的本质
模块 A 依赖模块 B,但本地没有 B 的 jar,编译就失败。你有两个选择:
| 方式 | 优点 | 缺点 |
|---|---|---|
A. mvn install 被依赖的模块 |
简单,不需要改任何东西 | 每次改了依赖模块的代码都要重新 install |
| B. 在 IDEA 中建立模块间引用 | 改代码实时生效,不用反复 install | 需要配置正确 |
4.2 方式 A:按依赖顺序 install(推荐新手先用这个)
按照依赖图从最底层开始 install:
bash
cd module-common
mvn clean install -DskipTests
cd ../module-dao
mvn clean install -DskipTests
cd ../module-service
mvn clean install -DskipTests
cd ../module-web
mvn clean install -DskipTests
为什么不能一次性全 install? 因为有些模块之间可能有循环依赖,或者 Maven 不知道构建顺序。从最底层开始逐个 install 最稳妥。
4.3 方式 B:在 IDEA 中建立模块间引用(开发效率更高)
如果你已经在同一个 IDEA 项目中导入了所有模块,IDEA 通常会自动识别模块间依赖关系。验证方法:
- File → Project Structure → Modules
- 选中
module-web,看右侧 Dependencies 标签 - 如果看到
module-service且 Scope 是 Module(不是 JAR),说明 IDEA 已经建立了模块间引用 - 如果是 JAR 形式依赖,说明走的是本地 Maven 仓库
强制 IDEA 使用模块引用而不是 JAR:
确保所有模块在同一个 IDEA Project 中,且模块名称与 pom.xml 中的 artifactId 一致。IDEA 会自动把 Maven 依赖解析为模块引用。
4.4 依赖下载失败怎么办
arduino
Could not resolve dependencies: Could not find artifact com.yourcompany:xxx:jar:1.0.0
- 这个模块可能在 Nexus/Artifactory 私有仓库,检查
~/.m2/settings.xml中的<mirrors>和<servers>配置 - 问同事要一份正确的
settings.xml - 确认版本号是否正确,有时
pom.xml里的版本和仓库里实际部署的版本不一致
五、第四步:找到启动入口并运行
5.1 定位启动类
通常在 web 或 bootstrap 模块中:
bash
# 在所有模块中搜索
find . -name "*Application.java"
# 或者搜索 Spring Boot 启动注解
grep -r "@SpringBootApplication" --include="*.java" .
5.2 在 IDEA 中配置 Run Configuration
- 找到带
main方法的启动类 - 右键 → Run 'XXXApplication.main()'
或者手动配置 Run → Edit Configurations → + → Application:
| 配置项 | 填写内容 |
|---|---|
| Name | 自定义,如 module-web |
| Main class | 选择启动类 |
| Use classpath of module | 选择启动模块(如 module-web) |
| Working directory | $MODULE_WORKING_DIR$(默认即可) |
| JRE | 1.8 |
| VM options | -Xms512m -Xmx2g -Dspring.profiles.active=dev |
5.3 配置文件加载问题
启动时最常见的报错就是找不到配置文件:
bash
Could not resolve placeholder 'xxx' in value "${xxx}"
application.yml not found
排查思路:
- 确认配置文件在启动模块的
src/main/resources/下 - 多环境配置:检查
application-{profile}.yml,确认 VM options 里设置了-Dspring.profiles.active=dev - 外部配置:有些公司把配置文件放在外部目录,检查是否有
-Dspring.config.location=/path/to/config/
六、第五步:日常开发工作流
6.1 修改了被依赖的模块
如果你改的是底层模块(比如 module-common),并且使用方式 A(JAR 依赖):
bash
cd module-common
mvn clean install -DskipTests
然后在 IDEA 中点击 Reload All Maven Projects(Maven 窗口的刷新按钮)。
如果你使用的是方式 B(IDEA 模块引用),不需要手动 install,IDEA 会自动编译。
6.2 快速定位类在哪个模块
- 双击 Shift:全局搜索类名
- 搜索结果右侧会标注属于哪个模块
- 这样你就知道要用这个类,需要在
pom.xml里依赖哪个模块
6.3 查看跨模块调用链
- 右键某个方法 → Find Usages(Alt+F7)
- 可以看到哪些模块的哪些类在调用它
- 帮助你追踪一个请求从 Controller → Service → Dao 的完整链路
七、第六步:排查常见坑
7.1 版本不一致导致的问题
css
java.lang.NoSuchMethodError: com.xxx.Service.doSomething()
不同模块依赖了同一 jar 的不同版本。排查:
bash
cd module-web
mvn dependency:tree -Dverbose | grep "omitted for conflict"
解决 :在父级或 BOM 中统一版本,或者在 pom.xml 中显式声明版本号。
7.2 循环依赖
如果模块 A 和模块 B 互相依赖,Maven 会报:
css
The projects in the reactor contain a cyclic reference
这种情况在独立仓库中更常见,因为 A 和 B 是分开构建的。
临时绕过:
- 先
mvn install模块 A(此时可能用了一个旧版本的 B) - 再
mvn install模块 B - 再
mvn install模块 A(此时就能拿到最新的 B)
根本解决 :把互相依赖的部分抽到 module-common-api 中。
7.3 本地仓库污染
有时候本地 Maven 仓库里的 jar 是坏的(下载中断、版本不对等):
bash
# 清理某个特定依赖
rm -rf ~/.m2/repository/com/yourcompany/module-service/
# 然后重新 install
cd module-service
mvn clean install -DskipTests
7.4 IDEA 缓存导致的问题
明明代码改了,但 IDEA 还是报旧的编译错误:
- File → Invalidate Caches / Restart → Invalidate and Restart
- 或者删除项目下的
.idea目录,重新导入
八、第七步:进阶 --- 用 Maven Helper 插件
强烈推荐安装 Maven Helper 插件:
- File → Settings → Plugins → 搜索 "Maven Helper" → 安装
- 打开任意模块的
pom.xml,底部会出现 Dependency Analyzer 标签 - 按 Conflicts 排序,红色就是版本冲突
- 右键冲突依赖 → Exclude ,自动添加
<exclusion>标签
九、总结:新手上手路线图
sql
Day 1: Clone 所有仓库 → 全部导入同一个 IDEA 项目 → 确认 JDK 版本
→ 按依赖顺序 mvn install -DskipTests → 找到启动类 → 跑起来
Day 2: 看每个模块的 pom.xml → 画出依赖关系草图 → 理解数据流向
Day 3: 从入口模块开始,追踪一个完整请求的处理链路
(Controller → Service → Dao → 数据库)
Day 4+: 尝试改一个小功能,验证你理解的依赖关系是否正确
记住三个核心原则:
- 从最底层开始 install ,
common → dao → service → web,顺序不能反 - 所有模块导入同一个 IDEA 项目,IDEA 会自动把 JAR 依赖解析为模块引用,开发时改代码不用反复 install
- 问同事要一份能编译通过的
settings.xml,很多"跑不起来"的问题其实是 Maven 仓库配置不对
这种架构虽然看着散,但好处是每个模块独立演进、独立发布。把依赖关系搞清楚了,剩下的就是日常开发的事。
了解更多,请关注我的微信公众号,感谢!
