实际的开发项目中,经常会使用maven搭建聚合项目或父子模块,比如说现在的spring cloud微服务项目,需要把API接口和具体的业务逻辑分开,API可以打成jar包给其它模块项目用feign调用。另外例如一些SpringFramework框架,它的项目结构就是聚合多模块结构;我们使用的Spring-Boot项目中也算是一种父子模块结构。所以了解这部分知识对我们将来看一个陌生项目的结构还是很有帮助的。
这篇博客就介绍Maven关于聚合项目和父子模块的相关知识,聚合项目和父子项目没有什么联系,这里我们分别来介绍它们。
聚合项目又称为多模块项目,这种结构的目的是为了统一构建项目,也就是说我对根项目的任何mvn 命令操作,都会相应的执行到每一个被聚合的module项目中。想象一下,如果你创建了10个项目,如果你要对这10个项目进行 mvn install操作(将项目发布到本地仓库),难道要单独的进行10遍操作么?
实际点,我们来看一看像spring-framework这种框架内维护的项目内部是什么样子。
内部大概是22个子项目,如果每一个都要手动去执行mvn命令,那真的也是无聊的操作了。看一看它的根项目中的setting.gradle中的聚合内容。(spring-framework默认gradle构建,不用担心,把它当作maven看待即可。)
所以为了解决这种耗时又无聊的操作,项目构建工具如maven提供的聚合特性的好处就来了,只需要对根项目操作一次命令即可。
有一点要清楚,聚合仅仅是为了方便我们管理多个项目,提高效率。它和父子模块没有半点关系,被聚合的模块基本感知不到根模块的存在
下面我们来动手搭建聚合项目。
2. 添加子模块。
我用的是idea,所以右键添加module即可。
通过
同时创建的其它模块默认在maven-demo项目目录下一级创建,实际上项目目录层级没有要求,如果项目层级不同,则需要修改module标签内的相对路径,这里我们手动将second-module项目移到first-demo项目目录下看一看。
在单纯的聚合项目中,被聚合的项目是没有上下级或者说父子级区别的,都是相同的级别。
3. 现在发布所有模块到本地仓库,只需要在maven-demo下,执行一次 mvn install 命令即可。
注意执行命令的目录。
H:\IdeaProjects\maven-demo>mvn install
可以看到所有的聚合模块都会执行。
[INFO] first-moudle ....................................... SUCCESS [ 1.505 s]
[INFO] second-moudle ...................................... SUCCESS [ 0.067 s]
[INFO] mavendemo .......................................... SUCCESS [ 1.438 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.116 s
[INFO] Finished at: 2021-02-07T22:51:10+08:00
[INFO] Final Memory: 16M/168M
[INFO] ------------------------------------------------------------------------
父子模块这种项目结构,本质上就是继承关系。上边我们说过聚合模块结构没有上下级区分,但这里的父子模块就要区分上下级了(这里的上下级不是指文件目录的上下级),子模块会继承父模块的相关依赖配置。
继承在java里的好处就是子类可以使用父类的属性和方法,减少代码冗余。
maven这里同样也是这个好处:
之前我们在聚合项目那里说过,被聚合的模块根本无法感知到根模块的存在。父子模块正好相反,父模块根本无法感知到哪个子模块把它当作爸爸。
这也是为什么实际项目中,我们在父模块中聚合子模块,同时子模块中又继承父模块。我们作为一个第三者局外人,得清楚它们之间的关系,方便我们统一管理。当然你使用ide创建父子模块时,默认就会保持这种关系(既是聚合项目关系,又是父子模块关系)。
这里我们搭建一个单纯的父子模块,也就是不在父模块中配置module标签,仅在子模块中指定它的父模块是谁。父亲不知道儿子是谁,儿子却知道自己的爹在哪里。
1.创建父模块
父子模块中,父模块一般作为子模块依赖的管理,它只需要定义好依赖的版本和必须的依赖即可。
父模块的打包方式必须为pom。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.binghuazheng.maven</groupId>
<artifactId>mavendemo</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<properties>
<commons.lang3.version>3.8</commons.lang3.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
父模块添加了junit依赖,指定了commons-lang3依赖的版本,并没有指定聚合的模块。
2.创建子模块
子模块需要通过
这里就可以引入父模块的junit。并且根据父模块的commons-lang3版本,直接依赖即可。
在我们实际开发中,一般都是将聚合和父子这两种关系混合使用,这里我拆分说,只是为了分别去理解它们各自的作用。
不论父子模块还是聚合模块,根模块的打包方式都必须是pom,下面的模块可以是jar或者war这两种打包方式。
聚合模块这种项目结构,仅仅是为了方便统一管理操作所有的模块。根模块和它内部
父子模块这种项目结构,仅仅是为了方便子模块对依赖的管理,子模块通过
当然混合使用才能发挥它们最大的优势!