Maven是一个Java项目管理和构建工具,它可以定义项目结构、项目依赖,并使用统一的方式进行自动化构建,是Java项目不可缺少的工具。

Maven就是是专门为Java项目打造的管理和构建工具,它的主要功能有:

一个使用Maven管理的普通的Java项目,它的目录结构默认如下: 一个Maven项目的标准目录结构:

所有的目录结构都是约定好的标准结构,我们千万不要随意修改目录结构。使用标准结构不需要做任何配置,Maven就可以正常使用。

一个Maven工程就是由groupId,artifactId和version作为唯一标识。我们在引用其他第三方库的时候,也是通过这3个变量确定。例如,依赖commons-logging:

Maven解决了依赖管理问题。例如,我们的项目依赖abc这个jar包,而abc又依赖xyz这个jar包: 当我们声明了abc的依赖时,Maven自动把abc和xyz都加入了我们的项目依赖,不需要我们自己去研究abc是否需要依赖xyz。 因此,Maven的第一个作用就是解决依赖管理。我们声明了自己的项目需要abc,Maven会自动导入abc的jar包,再判断出abc需要xyz,又会自动导入xyz的jar包,这样,最终我们的项目会依赖abc和xyz两个jar包。

Maven定义了几种依赖关系,分别是compile、test、runtime和provided: 其中,默认的compile是最常用的,Maven会把这种类型的依赖直接放入classpath。 test依赖表示仅在测试时使用,正常运行时并不需要。最常用的test依赖就是JUnit:

runtime依赖表示编译时不需要,但运行时需要。最典型的runtime依赖是JDBC驱动,例如MySQL驱动:

provided依赖表示编译时需要,但运行时不需要。最典型的provided依赖是Servlet API,编译的时候需要,但是运行时,Servlet服务器内置了相关的jar,所以运行期不需要:

最后一个问题是,Maven如何知道从何处下载所需的依赖?也就是相关的jar包?答案是Maven维护了一个中央仓库(,所有第三方库将自身的jar以及相关信息上传至中央仓库,Maven就可以从中央仓库把所需依赖下载到本地。 Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过,就会被Maven自动缓存在本地目录(用户主目录的.m2目录),所以,除了第一次编译时因为下载需要时间会比较慢,后续过程因为有本地缓存,并不会重复下载相同的jar包。

通过上述3个变量,即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改。修改已发布jar包的唯一方法是发布一个新版本。 因此,某个jar包一旦被Maven下载过,即可永久地安全缓存在本地。 注:只有以-SNAPSHOT结尾的版本号会被Maven视为开发版本,开发版本每次都会重复下载,这种SNAPSHOT版本只能用于内部私有的Maven repo,公开发布的版本不允许出现SNAPSHOT。

除了可以从Maven的中央仓库下载外,还可以从Maven的镜像仓库下载。如果访问Maven的中央仓库非常慢,我们可以选择一个速度较快的Maven的镜像仓库。Maven镜像仓库定期从中央仓库同步: 中国区用户可以使用阿里云提供的Maven镜像仓库。使用Maven镜像仓库需要一个配置,在用户主目录下进入.m2目录,创建一个settings.xml配置文件,内容如下:

最后一个问题:如果我们要引用一个第三方组件,比如okhttp,如何确切地获得它的groupId、artifactId和version?方法是通过search.maven.org搜索关键字,找到对应的组件后,直接复制:

Maven不但有标准化的项目结构,而且还有一套标准化的构建流程,可以自动化实现编译,打包,发布,等等。

使用Maven时,我们首先要了解什么是Maven的生命周期(lifecycle)。 Maven的生命周期由一系列阶段(phase)构成,以内置的生命周期default为例,它包含以下phase:

所以,我们使用mvn这个命令时,后面的参数是phase,Maven自动根据生命周期运行到指定的phase。 更复杂的例子是指定多个phase,例如,运行mvn clean package,Maven先执行clean生命周期并运行到clean这个phase,然后执行default生命周期并运行到package这个phase,实际执行的phase如下:

大多数phase在执行过程中,因为我们通常没有在pom.xml中配置相关的设置,所以这些phase什么事情都不做。 经常用到的phase其实只有几个:

执行一个phase又会触发一个或多个goal: goal的命名总是abc:xyz这种形式。 看到这里,相信大家对lifecycle、phase和goal已经明白了吧? 其实我们类比一下就明白了:

大多数情况,我们只要指定phase,就默认执行这些phase默认绑定的goal,只有少数情况,我们可以直接指定运行一个goal,例如,启动Tomcat服务器:

通常情况,我们总是执行phase默认绑定的goal,因此不必指定goal。

我们在前面介绍了Maven的lifecycle,phase和goal:使用Maven构建项目就是执行lifecycle,执行到指定的phase为止。每个phase会执行自己默认的一个或多个goal。goal是最小任务单元。 我们以compile这个phase为例,如果执行:

Maven将执行compile这个phase,这个phase会调用compiler插件执行关联的compiler:compile这个goal。 实际上,执行每个phase,都是通过某个插件(plugin)来执行的,Maven本身其实并不知道如何执行compile,它只是负责找到对应的compiler插件,然后执行默认的compiler:compile这个goal来完成编译。 所以,使用Maven,实际上就是配置好需要使用的插件,然后通过phase调用它们。 Maven已经内置了一些常用的标准插件: 如果标准插件无法满足需求,我们还可以使用自定义插件。使用自定义插件的时候,需要声明。例如,使用maven-shade-plugin可以创建一个可执行的jar,要使用这个插件,需要在pom.xml中声明它:

自定义插件往往需要一些配置,例如,maven-shade-plugin需要指定Java程序的入口,它的配置是:

注意,Maven自带的标准插件例如compiler是无需声明。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注