我们开发一个很大的项目工程时,会用到很多模块或者子工程进行同步开发,如
CommonModel:公共的基础服务,比如工具类、常量类等等;
BussinessModel:业务模块,是系统真正要实现的业务,依赖于 common 模块,比如菜单管理、订单管理、权限管理、角色管理等;
Application:可发布的 web 应用,由各个 BussinessModel 组成,最终满足项目整体需求;
第三方模块(Library):包括各类框架,Spring、Springboot、SpringCloud等
Maven 管理多模块应用的实现是互联网项目中多使用分布式开发,每个独立的服 务都会使用独立的项目进行维护,那么这样就需要使用多模块应用管理,来实现项目的高度统一
Maven进行多模块工程管理主要有如下三种方式
(1)File----New----Project,选择Empty Project,点击Next
(2)输入工程名,以及存放路径
Project name:项目名称
Project location:项目存放位置路径
(1)File----New----Module
(2)选择Maven工程,是否选择模板创建,如果只是普通Java项目可直接下一步,不用勾选
普通java项目(可选可不选,不选默认是普通Java工程)
(3)输入父工程,模块名,模块存放位置,以及模块坐标(gav)信息
Parent:父工程名(如果创建的工程本身就是父工程,这里选择None)
Name:子工程/模块名
Location:子工程/模块存放位置路径
GroupId:公司域名的倒序
ArtifactId:项目或模块名称
Version:项目或模块版本号
(4)配置导入设置
Maven 项目被修改后,需要“手动更新”或“自动更新”,通常选择右下角弹出框的
“Enable Auto-Import”
maven父工程必须遵循两点要求:
1、packaging标签的文本内容必须设置为pom
2、将src目录删除掉
(5)设置父工程的 pom.xml 文件
maven父工程必须遵循两点要求:
1、packaging标签的文本内容必须设置为pom
2、将src目录删除掉
此时可以看到 pom.xml 文件中内容如下
4.0.0
com.mycompay
maven-modules-1-parent
1.0.0
pom
(6)删除 src 文件目录
如果有子工程\模块,会看到左上角有一个 m↓ 标记,点击选择可以跳转的子模块/工程
(1)File----New----Module
(2)选择Maven工程,是否选择模板创建,如果只是普通Java项目可直接下一步,不用勾选
如果是web子模块,勾选如下
(3)选择父工程模块
Add as module to:选择将创建的模块添加到哪个模块下(老版本IDEA中有)
Parent:选择模块的父工程
GroupId:选择父工程后,默认继承父工程的 GroupId 值
ArtifactId:模块的项目名称
Version:选择父工程后,默认继承父工程的 Version 值
如果我们直接选择父工程,右键 “File----New----Module”,则这里会 parent 自动带出父工程名称
如果是2019版本IDEA,会有 Add as module to 这个选项,在这里选择None
博主当前使用的2021版本IDEA,因此没有 Add as module to 这个选项
在parent选择父工程之后,GroupId和Version会自动带出
如下是2021版IDEA
如下是2019版IDEA
web子模块同理
我们发现子模块的 pom.xml 文件左上角有一个 m↑ 这个标记,点击可跳转到父工程的 pom.xml 文件中
web子模块视图,packing标签多了一个 war
指向父工程
相对路径(父工程的 pom.xml 文件相对路径)
除了子模块名可以修改,其他公司域名,version等都是继承父工程
maven-modules-1-parent
com.mycompany
1.0.0
../maven-modules-1-parent/pom.xml
4.0.0
maven-modules-1-java
按照上述创建子模块方式,选择父模块为上一级子模块即可
我们可看下创建后的视图
(1)File----New----Project
(2)选择Maven工程,是否选择模板创建,如果只是普通Java项目可直接下一步,不用勾选(这里不用勾选,Java和web工程都无所谓)
(3)设置父工程项目名称和项目存放位置;并填写坐标(gav)信息
Maven 项目被修改后,需要“手动更新”或“自动更新”,通常选择右下角弹出框的
“Enable Auto-Import”
(5)将本maven工程修改为父工程
【1】设置 pom.xml 文件的 packing标签为 pom
【2】删除 src 目录
如果父工程下有子模块,在父工程的 pom.xml 文件
会有
(1)File----New----Module
(2)选择Maven工程,Java工程可直接下一步
(3)选择父工程
Add as module to:选择将创建的模块添加到哪个模块下(老版本IDEA中有)
Parent:选择模块的父工程
GroupId:选择父工程后,默认继承父工程的 GroupId 值
ArtifactId:模块的项目名称
Version:选择父工程后,默认继承父工程的 Version 值
如果我们直接选择父工程,右键 “File----New----Module”,则这里会 parent 自动带出父工程名称
注:
如果是2019版本IDEA,会有 Add as module to 这个选项,在这里选择父工程,和 Parent 选项的父工程保持一致
博主当前使用的2021版本IDEA,因此没有 Add as module to 这个选项
在parent选择父工程之后,GroupId和Version会自动带出
如下是2021版IDEA
如下是2019版IDEA
(4)创建之后视图
子模块就在父工程目录之下了
同理,再创建一个web工程
此时,工程目录如下
我们再去看一下父工程的 pom.xml 文件
此时会多一个
同理,我们也可以按照上述方式给子模块在创建子模块下的子模块(第三层,第四层......第N层等)
指将多个模块整合在一起,统一构建,避免一个一个的构建。聚合需要个父工程,然后使用
聚合POM与继承中的父POM的packaging都必须是pom;同时,聚合模块与继承中的父模块除了POM外,都没有实际的内容
如我们可以以第一种方式创建多个Maven父工程,再以第二种方式在每个父工程下创建子工程混合使用
Maven项目中会统一使用 JDK 版本和编译级别,将编 译插件添加到父工程,子模块依然会无条件去继承父工程的插件
1、查看编译级别
File ----> Settings ----> Build, Execution, Deployment ----> Compiler ----> Java Compiler
2、在父工程中的 pom.xml 文件 build ----> plugins 标签中添加编译插件
maven-compiler-plugin
3.1
1.8
UTF-8
如下
修改完成之后,我们点击右边工具栏的中的 Maven,点击 “刷新”按钮即可
此时再去查看,都变为 1.8版本了
Maven多模块管理的实质:实现依赖的版本统一管理
如果每个子模块都有自己依赖的jar包,且版本不同,那么在工程代码合并时会造成很大冲突,如子模块1 使用 mysql 5.1版本,而子模块2 使用 mysql 8.0版本,势必造成版本不统一,且有些参数,函数方法等会找不到等问题,那么合项目也是很大的困难
如下,我们在子模块maven-modules-1-java的 pom.xml文件 有Junit和 mysql5.1.49 依赖,刷新
在子模块 maven-modules-1-web的 pom.xml文件 有mysql8.0.19 依赖,刷新
这样就导致了两个子模块的 mysql 依赖版本不同,势必会出错
那么我们将子模块下的 pom.xml 文件里面的所有依赖都添加到 父工程下,删掉子模块下的 依赖
此时发现所有工程/模块(包括父工程,所有子模块)都有父工程 pom.xml 文件中添加的所有依赖jar包,如下
以上写做法,子模块会无条件继承父工程的所有依赖,导致的问题是,造成依赖 jar 包的 冗余 和 空间的浪费,本不需要的继承 的依赖也会被继承,这就大大增加了项目模块最终打包的大小,也可能未上线埋下了隐患。
父工程管理的是所有项目模块的依赖,而不是某一个项目模块的依赖,所以 某一个项目模块不需要继承父工程中的所有依赖,这就需要子项目模块向父工程声明需要的 依赖即可(声明式依赖)
此时,父工程实际只需要管理依赖的版本号即可
1、在父工程添加依赖管理,使用
子模块项目之前继承的依赖消失,由于父工程通过 dependencyManagement 标签管理依 赖,那么之前子模块无条件继承的依赖就全部消失
2、自定义标签名称
在 Maven 的 pom.xml 文件中,
POM 中通过${property_name}的形式引用变量的值,标签名称一般由 项目名称 + 字段version组成
单个单词可直接 XX.version命名,多个单词可横线分割 XX-XX-version
父工程 pom.xml 文件
4.0.0
com.mycompany
maven-modules-1-parent
1.0.0
pom
4.10
8.0.19
2.6.2
4.3.16.RELEASE
junit
junit
${junit.version}
mysql
mysql-connector-java
${mysql-connector-java-version}
maven-compiler-plugin
3.1
1.8
UTF-8
3、子模块声明式添加依赖
由于父工程管理依赖的版本号,那么子模块要想继承依赖,只能通过声明式来添加依赖
实际上,子模块中的依赖是继承父工程依赖的版本号
如果子模块已定义依赖版本号,那么 以子模块定义的版本号为准
子工程 pom.xml 文件
maven-modules-1-parent
com.mycompany
1.0.0
../maven-modules-1-parent/pom.xml
4.0.0
maven-modules-1-java
pom
mysql
mysql-connector-java
5.1.49
这时我们查看右方工具栏中的 Maven,可看到其他没写依赖的子模块,不会有依赖,只有声明要继承依赖的子模块才会有
项目中多个模块间公共依赖的版本号、scope的控制
一个项目有很多模块,每个模块都会用到一些公共的依赖。这些公共的依赖若交由各个模块独自管理,若每个模块同一个依赖的版本号不一致,会造成很大问题
1、如 module-1 使用mysql5.7,module-2使用mysql8.0 ,那么mysql5.7和8.0之间有区别的特性,方法没法公用
2、打包和开发测试环境下对同一jar包不同版本号的处理可能不一致,造成运行时和测试时结果不一致项目升级时,会造成修改版本号时遍地开花的问题
dependencyManagement 标签通常适用于多模块环境下定义一个top module来专门管理公共依赖的情况
与dependencies标签下dependency的区别:
1、所有声明在dependencies里的依赖都会自动引入,并默认被所有的子项目继承dependencies
2、即使在子项目中不写该依赖项,那么子项目仍然会从父项目depenManagement中继承该artifactId和groupId依赖项(全部继承),若没有则报错。
3、dependencyManagement只是声明依赖的版本号,该依赖不会引入,因此子项目需要显示声明所需要引入的依赖,若子项目 中dependencies中的dependency声明了version,则父项目中dependencyManagement中的声明无效