解释之前,提个小问题
假如你正在Eclipse下开发两个Java项目,姑且把它们称为A、B,其中A项目中的一些功能依赖于B项目中的某些类,那么如何维系这种依赖关系的呢?
很简单,这不就是跟我们之前写程序时一样吗,需要用哪个项目中的哪些类,也就是用别人写好了的功能代码,导入jar包即可。所以这里也如此,可以将B项目打成jar包,然后在A项目的Library下导入B的jar文件,这样,A项目就可以调用B项目中的某些类了。
如果在开发过程中,发现B中的bug,则必须将B项目修改好,并重新将B打包并对A项目进行重编译操作。
在完成A项目的开发后,为了保证A的正常运行,就需要依赖B(就像在使用某个jar包时必须依赖另外一个jar一样),两种解决方案,第一种,选择将B打包入A中,第二种,将B也发布出去,等别人需要用A时,告诉开发者,想要用A就必须在导入Bjar包。两个都很麻烦,前者可能造成资源的浪费(比如,开发者可能正在开发依赖B的其它项目,B已经存储到本地了,在导入A的jar包的话,就有了两个B的jar),后者是我们常遇到的,找各种jar包,非常麻烦(有了maven就不一样了)。
上面问题的描述,其实都属于项目与项目之间依赖的问题,人为手动的去解决,很繁琐,也不方便,所以使用maven来帮我们管理。
简介
Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件,用于构建多模块工程。Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。
主要功能
1.构建工具
① 含义
构建工具的具体意思其实是打包项目,最终的目的是要把平日写出的代码项目集成一个可部署的工具的过程,但由于Maven负责项目的自动化构建,所以这需要编程人员要约定基本项目的目录结构,即为什么文件夹放什么文件,这个文件夹要干什么的。
② 约定的目录结构
一般正常项目目录构建基本都是以图1-1为准,结构:[1] 工程名 、 [2] src目录:源码 、 [3] pom.xml文件:Maven工程的核心配置文件 、[4] main目录:存放主程序、 [5] test目录:存放测试程序、 [6] java目录:存放Java源文件、 [7] resource目录:存放框架或其他工具的配置文件。
③ 构建流程
Maven的构建大致分为以下步骤,如图1-2
1-2
Clean清空编译结果,为下一次编译做准备。(执行命令:mvn clean)
Compile编译主程序源文件,Maven将源文件分为主程序源文件和测试程序源文件,他们放在不同的目录。(执行命令:mvn compile)
Test编译测试程序源文件。(执行命令:mvn test)
Package将主程序编译后的class文件、资源文件以及配置文件,打包为对应的类型(jar包或war包,需要在pom.xml中设置)。(执行命令:mvn package)
Install将打包后的文件按照一定规则(groupId+artifactId的方式)安装到本地仓库中。(执行命令:mvn install)
Deploy部署程序。(执行命令:mvn deploy)
2.依赖管理
①.含义
Maven 一个核心的特性就是依赖管理。当我们处理多模块的项目(包含成百上千个模块或者子项目),模块间的依赖关系就变得非常复杂,管理也变得很困难。针对此种情形,Maven 提供了一种高度控制的方法。这也是Maven最重要的功能,通过工程的唯一标识(groupId+artifactId+version)可以明确指明依赖的库及版本,而且能够处理依赖关系的传递。maven可以指定依赖的作用范围(scope)。
②.依赖原则
由于Maven遵循可传递性依赖,所以直接依赖和间接依赖,之间的项目是可以互相识别的,如图1-3
1-3
Maven会将B加入工程A中,而项目C作为A的间接依赖,也为加入到A中,我们叫这种情况为依赖传递。正因为传递依赖的概念的引出,所以依赖传递拉出了一个先后顺序的原则,分别是:就近原则+声明先后原则。
(1).就近原则
如下图1-4
项目C有两个版本,分别是V1和V2版本。项目A直接依赖B和C V2版本,B直接依赖C的V1版本,此时Maven会通过就近原则添加C V2版本。就近原则基本是按步长来计算的。
(2).声明先后原则
如下图1-5
1-5
如果A到达C的两个版本的步长是相同的,Maven会按pom中的定义的先后顺序加入对应的依赖,先定义的会加入到A的依赖中。
③.依赖范围
依赖的范围和构建的阶段(过程)是密不可分的,Maven使用scope标签来标识依赖的范围,pom代码如下图1-6
1-6
具体阶段范围依赖情况如下图1-7
1-7
(3).工程聚合
①.目的
为了在开发过程中更清晰、更有效地复用模块进行开发子系统使用maven将模块工程化开发,将每个模块创建为一个maven工程。前面提到pom类型用于于构件多模块工程,这体现了project之间的一种聚合关系:将一系列小的模块聚合成整个产品。通过聚合后的工程可以同时管理每个相关模块的构建、清理、文档等工作。聚合关系通过在子工程中指定一个pom类型的project作为父project来定义。
②.继承与依赖
想要实现聚合的效果,就需要在众多工程之中,建立一个父工程,只需要在父工程的POM文件中加入标签即可,代码如下:
<modules>
<module>tuling-client</module>
<module>tuling-server</module>
</modules>
聚合多模块维护如下图1-8
1-8
继承
而基于父工程所创建的聚合模块也会牵引出子工程下的继承关系继承是指子工程直接继承父工程当中的属性、依赖、插件等配置,避免重复配置。
配置继承结构:
1.说到继承肯定是一个父子结构,那么我们在aggregator中来创建一个parent project
2.: 作为父模块的POM,其打包类型也必须为POM
3.结构:父模块只是为了帮助我们消除重复,所以它也不需要src/main/java、src/test/java等目录
4.新的元素: , 它是被用在子模块中的
5.元素的属性:: 表示父模块POM的相对路径,在构建的时候,Maven会先根据relativePath检查父POM,如果找不到,再从本地仓库查找
6.relativePath的默认值:…/pom.xml
7.子模块省略groupId和version:使用了继承的子模块中可以不声明groupId和version, 子模块将隐式的继承父模块的这两个元素
依赖
通过继承的特性,子工程是可以间接依赖父工程的依赖,但多个子工程依赖有时并不一至,这时就可以在父工程中加入 声明该功程需要的JAR包,然后在子工程中引入。
具体代码展示:
<!-- 父工程中声明 junit4.12 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</dependencyManagement>
<!--子工程中引入 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
包括项目属性可以通过<properties> 配置 属性参数,可以简化配置。
<!--配置proName属性 -->
<properties>
<proName>ddd</proName>
</properties>
<!--引用方式 -->
${proName}
maven 默认的属性
${basedir}项目根目录
${version}表示项目版本;
${project.basedir}同${basedir};
${project.version}表示项目版本,与${version}相同;
${project.build.directory}构建目录,缺省为target
${project.build.sourceEncoding}表示主源码的编码格式;
${project.build.sourceDirectory}表示主源码路径;
${project.build.finalName}表示输出文件名称;
${project.build.outputDirectory}构建过程输出目录,缺省为target/classes
总 结
总体来说Maven是项目代码和依赖文件的管理工具,面对自己的项目而言能够有效快速的实现项目部署和编译,面对依赖文件项目而言能够快速的实现功能使用和工具类的引入,从而减少编程人员繁琐的文件操作,更好的面向代码本身。
小普持续推出有价值的文章,关注“普适极客”👇
♥一起在技术研发的最前沿共同成长!♥