你真的了解Maven吗?
作者:鱼仔
博客首页: https://codeease.top
公众号:Java鱼仔
# (一)什么是Maven
Maven是Apache下的一个开源项目,目前可以用于构建和管理任何基于 Java 的项目的工具,让 Java 开发人员的日常工作更轻松。为了让开发人员更轻松,Maven做到了以下几点:
# 简化构建过程
提供了标准的、跨平台的自动化项目构建方式。Maven 并没有消除了解底层机制的需要,但是Maven确实让Java项目的构建变得更简单了。
# 提供统一的构建系统
Maven 使用其项目对象模型 (POM) 和一组插件来构建项目。一旦你熟悉了一个 Maven 项目,你就会知道所有的 Maven 项目是如何构建的。这在浏览开源项目和其他项目时会十分节省时间。
# 依赖管理
更加方便快捷地管理项目依赖的Jar包,同时可避免不同Jar包版本之间的冲突。
# (二)Maven中的基础概念
# 仓库
仓库中存储了各种Jar包,Maven本身维护了一个包含全球大部分Jar包的仓库,称为中央仓库,可以在Maven提供的网站中搜索需要的Jar包:https://search.maven.org/。
每个人的本地也会有一个Maven仓库称为本地仓库,当我们使用一些Jar包时,需要先从中央仓库拉取Jar包到本地仓库,再从本地仓库拉取到项目中。
一些公司为了更快的访问速度以及方便将本公司的Jar包给员工使用,会搭建 Maven私服仓库,私服仓库会定期读取中央仓库,也会维护自身的Jar包在里面。
# 坐标
坐标是用来描述maven中每个资源的位置,坐标主要通过三个标签来定位到一个资源:比如我上传到中仓仓库的一个Jar包:
<dependency>
<groupId>io.github.oliverliy</groupId>
<artifactId>fast-sso-client</artifactId>
<version>0.0.2</version>
</dependency>
2
3
4
5
groupId:当前Jar包所属的机构,通常采用域名反写的方式,我这里是使用了github的域名。
artifactId:当前项目名称,我上传的这个项目名称就叫fast-sso-client。
version:定义当前的项目版本。
# (三)Maven中的依赖管理
依赖是指一个项目所需的所有Jar包,在Maven中,统一将依赖放在dependencies下的dependency中。
<dependencies>
<dependency>
<groupId>io.github.oliverliy</groupId>
<artifactId>fast-sso-client</artifactId>
<version>0.0.2</version>
</dependency>
</dependencies>
2
3
4
5
6
7
# 4.1 依赖传递
Maven中的依赖具备依赖传递的功能,比如在上面这个例子中引入了fast-sso-client这个依赖包,而fast-sso-client又会依赖其他的Jar包,就如下图所示:
直接引入的依赖包称为直接依赖,被直接依赖带入项目的其他依赖包称为间接依赖。
# 4.2 依赖冲突
当一个项目中同时存在多个版本的依赖包时,就会出现依赖冲突的情况。Maven项目在选择依赖包时,会采取就近原则的方式。配置顺序靠前的会替换配置顺序靠后的,配置层级浅的会替换配置层级深的。
以上面这个依赖关系图来看,最终项目A依赖的Jar包分别是:1.0版本的依赖A和1.0版本的依赖B。
# 4.3 依赖冲突
如果想在项目中排除掉依赖包中的某个传递依赖时,可以通过exclude排除掉依赖。被排除的依赖无需指定版本。
<dependency>
<groupId>io.github.oliverliy</groupId>
<artifactId>fast-sso-client</artifactId>
<version>0.0.2</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
2
3
4
5
6
7
8
9
10
11
# 4.4 依赖范围
在依赖中可设置scope标签代表依赖的范围,可选参数有compile、provided、runtime、test,默认是compile。
<dependency>
<groupId>io.github.oliverliy</groupId>
<artifactId>fast-sso-client</artifactId>
<version>0.0.2</version>
<scope>compile</scope>
</dependency>
2
3
4
5
6
当scope为compile时,项目代码(main文件夹范围内)、测试代码(test文件夹范围内)和package打包指令下这个依赖都有效,绝大部分的Jar包都是compile。
当scope为test时,只有测试代码范围内是有效的,最常见的就是junit包,只会在测试代码里使用就可以将scope定为test。
当scope为provided时,表示在项目代码范围和测试代码范围内有效,但是不会被打包,常见的是servlet-api这个依赖,原因是如果将servlet-api打入jar包,就会和一些web容器里的servlet依赖冲突。
当scope为runtime时,主会在打包时生效,最常见的就是jdbc的驱动依赖,我们写jdbc代码时,驱动都是用全限定名的字符串指定的,因此在项目代码中根本就不会用到,只要在打包时把这个jar包打进去就行。
# (四)Maven的生命周期
maven的生命周期很长,但是我们只需要关注最常用的那些就可以了,在IDEA的maven插件中,就可以看到常用的生命周期:
从上往下代表了Maven的生命周期,当执行某个命令时,它往前的生命周期命令都会被执行,比如执行compile,那么会依次执行clean、validate、compile。
有的时候我们在打包时希望可以跳过测试,那么可以通过命令
mvn install -D skipTests
或者在IDEA中直接通过闪电符号快速跳过
其中比较常用的几个命令:clean会清除掉前一次的打包记录。compile会编译项目的源代码、package会将编译后的代码打包成文件,比如war包、jar包。install会安装项目包到本地仓库,这样其他项目就可以使用该项目包。deploy可以将项目包发送到远程仓库中。
# (五)Maven中的插件
插件和生命周期的每个阶段绑定,maven中的每个生命周期上都绑定有预设的功能,通过插件可以实现更多的自定义功能。比较常用的是打包插件,比如我现在想要打一个源码包,就可以在maven的官网找到对应的插件:
然后放到pom文件中去:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
其中groupId、artifactId、version就不用介绍了,executions表示插件执行的参数,其中goals对应官网中的goals
每个插件都有自己的goals,比如这个打源码包的插件,当选择jar时,就表示将源码文件打包到一个jar文件中去。 phase表示在哪个生命周期执行,选择test就表示在test这个生命周期内执行。
# (六)Maven中的模块聚合
为了更方便地管理整个项目的版本,往往会在父项目中将各个模块都会用到的依赖控制起来,防止每个模块用不同版本的依赖包,这个时候就需要用到<dependencyManagement>
。
首先在父工程中定义依赖包:
<dependencyManagement>
<dependencies>
<artifactId></artifactId>
<groupId></groupId>
<version></version>
</dependencies>
</dependencyManagement>
2
3
4
5
6
7
接着在每个子项目上用parent标签指出依赖的父工程是谁:
<parent>
<artifactId></artifactId>
<groupId></groupId>
<version></version>
</parent>
2
3
4
5
这样子工程就可以使用父工程里引入的依赖包了。
同样的方式可以管理插件,pluginManagement起到了和dependencyManagement一样的能力。
# (七)Maven的版本管理
在依赖包中,经常可以看到有些版本会带上SNAPSHOT,有些就不会带。这就是Maven的不同版本所附有的标识。
SNAPSHOT代表快照版本,也就是测试阶段版本,这个版本会随着开发进度不断更新。
RELEASE是发布版本,当项目开发达到某个相对稳定的阶段时,就可以对外发布相对稳定的版本,这种版本就是发布版本。
但是在maven库中,也能发现有些开源jar包命名并非是SNAPSHOT和RELEASE,这些还是按照每个企业自己的定义即可。