很早的时候接触到Maven,很多人都称呼其为"构建工具",过程中也是描述它是把源代码搞成一个发布的“构件”的东西,但是Maven它确实一个更复杂的东西“项目管理工具”。
在刚开始工作的时候最新接触到的打包工具是Ant,如果你接触过Ant你会发现Ant这种构件工具比较关注预处理,编译,打包,测试和分发等功能,而且需要写复杂的脚本,Maven可以说是提供了这些工具功能并具备其他的功能,Maven还可以生成报告,生成 Web 站点,虽然一直没有使用过用它维护站点,一般我都是使用Hexo、Jekyll或者现在刚换的gitbook等工具生成站点,这并不影响Maven成为一个构建的工具,它仅仅需要输入简单的命令就可以完成像是Ant那样写一堆的脚本完成的那些繁琐的工作,像是Package、install等,这些都得益于它抽象的生命周期,这些简单的生命周期消除了构建的重复并能很好的标准化构建过程,我还记得当时第一次知道Maven这个东西的时候就被它简单一致的构建概念深深吸引,其实最重要的感觉是“我靠,这玩意不用花太多的时间学习就能用”。
除了上面说的它是一个优秀的构建工具外,它也是一个优秀的依赖管理工具及项目信息管理工具,它提供了中央仓库可以帮助项目构建过程中自动下载依赖的jar包等,随着各个组织和公司开放的私服或者自己搭建私服依赖下载变得也越来越简单,如果对Nexux私服安装部署感兴趣的话可以参考Maven私服-Nexus
Maven同样也是一个跨平台的工具,或许很多人觉得跨平台是现在的标配,但是的确很多工具是没有办法跨平台使用的,Maven跨平台其实也是得益于基于JAVA开发的原因,在各个平台上操作命令统一,这样也是它能迅速推广流行的原因之一。
除了上面我们说的这些它的硬性的特性之外,使用Maven管理项目另外体会到的就是它约定优于配置(ConventionOver Configuration)的思想,它约定了项目目录结构、测试用例命名方式等,使用它只需要遵循这些成熟的规则即可,使用Maven还能享受一个额外的好处,即Maven对于项目目录结构、测试用例命名方式等内容都有既定的规则,只要遵循了这些成熟的规则即可,这就减少了我们拿到一个新的项目之后还要重新熟悉项目的目录结构构建方式等,不过约定优于配置肯定不是约定不允许配置,Maven很多默认行为还是可配置的,例如项目源码的资源文件的位置可以被自定义,JAR 文件的名字可以被自定义,在开发自定义插件的时候,几乎任何行为可以被裁剪以满足你特定的环境需求,如果你不想遵循约定,Maven 也会允许你自定义默认值来适应你的需求,但是项目开发过程中我一般不会允许项目中的成员开发中,或者其他人因为引入某些东西去随意更改项目的这些默认行为,如果滥用其允许更改的特性,那项目将慢慢变得面目全非。
那我们下面从对Maven安装目录进行介绍开始再简要介绍一下Maven的核心概念
一、maven的安装目录结构
bin
boot
conf
lib
LICENSE.txt
NOTICE.txt
README.txt
Bin
该目录包含了mvn运行的脚本,这些脚本用来配置Java命令,准备好classpath和相关的Java系统属性,然后执行Java命令。其中mvn是基于UNIX平台的shell脚本,mvn.bat是基于Windows平台的bat脚本。在命令行输入任何一条mvn命令时,实际上就是在调用这些脚本。该目录还包含了mvnDebug和mvnDebug.bat两个文件,同样,前者是UNIX平台的shell脚本,后者是windows的bat脚本。那么mvn和mvnDebug有什么区别和关系呢?打开文件我们就可以看到,两者基本是一样的,只是mvnDebug多了一条MAVEN_DEBUG_OPTS配置,作用就是在运行Maven时开启debug,以便调试Maven本身。此外,该目录还包含m2.conf文件,这是classworlds的配置文件。
Boot
该目录只包含一个文件,以maven 3.0为例,该文件为plexus-classworlds-2.2.3.jar。plexus-classworlds是一个类加载器框架,相对于默认的java类加载器,它提供了更丰富的语法以方便配置,Maven使用该框架加载自己的类库。更多关于classworlds的信息请参考http://classworlds.codehaus.org/。对于一般的Maven用户来说,不必关心该文件。
Conf
该目录包含了一个非常重要的文件settings.xml。直接修改该文件,就能在机器上全局地定制Maven的行为。一般情况下,我们更偏向于复制该文件至~/.m2/目录下(这里~表示用户目录),然后修改该文件,在用户范围定制Maven的行为。
Lib
该目录包含了所有Maven运行时需要的Java类库,Maven本身是分模块开发的,因此用户能看到诸如mavn-core-3.0.jar、maven-model-3.0.jar之类的文件,此外这里还包含一些Maven用到的第三方依赖如common-cli-1.2.jar、google-collection-1.0.jar等等。可以说,这个lib目录就是真正的Maven。关于该文件,还有一点值得一提的是,用户可以在这个目录中找到Maven内置的超级POM,
其他: LICENSE.txt记录了Maven使用的软件许可证Apache License Version 2.0;
NOTICE.txt记录了Maven包含的第三方软件;而README.txt则包含了Maven的简要介绍,包括安装需求及如何安装的简要指令等等。
二、Maven生命周期
Maven的生命周期是对所有的构建过程进行抽象和统一。Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作,生命周期只是定义了一系列的阶段,并确定这些阶段的执行顺序。而在执行这些阶段时,实际的工作还是由插件来完成的。
上面我们也说到过,生命周期包含一些阶段,这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段,用户和Maven最直接的交互方式就是调用这些生命周期阶段。
clean生命周期
clean生命周期的目的是清理项目,它包含三个阶段:
-
pre-clean 执行一些清理前需要完成的工作。
-
clean 清理上一次构建生成的文件。
-
post-clean 执行一些清理后需要完成的工作。
default生命周期
default生命周期定义了真正构件时所需要执行的所有步骤,它是生命周期中最核心的部分,它包含的阶段如下:
- validate 验证项目是否正确和所有需要的相关资源是否可用
- initialize 初始化构建
- generate-sources
- process-sources 处理源代码
- generate-resources
- process-resources 处理项目主资源文件。对src/main/resources目录的内容进行变量替换等工作后,复制到项目输出的主classpath目录中。
- compile 编译项目的主源代码
- process-classes
- generate-test-sources
- process-test-sources 处理项目测试资源文件
- generate-test-resources
- process-test-resources 处理测试的资源文件
- test-compile 编译项目的测试代码
- process-test-classes
- test 使用单元测试框架运行测试,测试代码不会被打包或部署
- prepare-package 做好打包的准备
- package 接受编译好的代码,打包成可发布的格式
- pre-integration-test
- integration-test
- postintegration-test
- verify
- install 将包安装到Maven本地仓库,供本地其他Maven项目使用
- deploy 将最终的包复制到远程仓库,供其他开发人员和Maven项目使用
site生命周期
site生命周期的目的是建立和发布项目站点,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。该生命周期包含如下阶段:
-
pre-site 执行一些在生成项目站点之前需要完成的工作
-
site 生成项目站点文档
-
post-site 执行一些在生成项目站点之后需要完成的工作
-
site-deploy 将生成的项目站点发布到服务器上
用户在mvn命令后可以指定三个生命周期中的任何阶段,则Maven会按以下逻辑执行:首先会得到该阶段所属生命周期,从该生命周期中的第一个阶段开始按顺序执行,直至该阶段本身。例如执行mvnclean命令会依次执行clean生命周期中的pre-clean阶段及clean阶段。mvn命令后可以指定多个阶段,Maven会按照输入的顺序依次执行,每次执行都会按照之前描述的逻辑执行
三、projectobject Model & Artifact & Repositories
projectobject Model
pom是一个xml,是maven工作的基础,执行任务时,maven会到项目根目录下读取pom.xml获得需要的配置信息
pom文件中包含了项目的信息和maven build项目所需的配置信息,通常有项目信息(如版本、成员)、项目的依赖、插件和goal、build选项等等
pom是可以继承的,通常对于一个大型的项目或是多个module的情况,子模块的pom需要指定父模块的pom
Artifact & Repositories
Artifact:一个项目将要产生的文件,可以是jar文件,源文件,二进制文件,war文件,甚至是pom
Repositories是用来存储Artifact的
Repositories分为本地仓库和远程仓库,远程仓库是指远程服务器上用于存储Artifact的仓库,本地仓库是指本机存储Artifact的仓库
四、Maven坐标
Maven坐标是一组可以惟一标识构件的三元组值
- groupId
代表构件的实体或组织例如:org.inspur.loushang,groupId一般遵循包路径的命名规范 - artifactId 实际的构件的名称,例如framework
- version,对应项目的版本号
- packaging 定义Maven项目打包的方式,首先,打包方式通常与所生成构件的文件扩展名对应,如上例中的packaging为jar,最终的文件名为my-app-0.0.1-SNAPSHOT.jar。也可以打包成war, ear等。当不定义packaging的时候,Maven 会使用默认值jar
- classifier: 该元素用来帮助定义构建输出的一些附件。附属构件与主构件对应,如上例中的主构件为my-app-0.0.1-SNAPSHOT.jar,该项目可能还会通过一些插件生成如my-app-0.0.1-SNAPSHOT-javadoc.jar,my-app-0.0.1-SNAPSHOT-sources.jar, 这样附属构件也就拥有了自己唯一的坐标
五、Maven仓库
如果说仓库的话必然需要说到使用JAR包,我们在pom.mxl通过jar包的坐标即通过groupId,artifactId,以及version确定一个唯一的jar包,如下:
<dependency>
<groupId>org.limingming</groupId>
<artifactId>test</artifactId>
<version>2.0.0-SNAPSHOT</version>
<!-- scope是声明这个jar包在生命周期中生效的范围。-->
<scope>compile</scope>
</dependency>
当项目构建过程中,如果我们依赖上面的jar包,会先去本地仓库查看是否有该资源,如果有的话,判断版本是否正确,如果一切都没问题则直接使用;否则会去中央仓库或者其他仓库中去寻找jar包,如果配置的仓库中有则会下载到本地并进行使用。
在Maven中会涉及到几种概念:
1 工作空间,即我们的项目工程,这里面可能会放着pom.xml文件,这个pom.xml就是maven的配置文件
2 本地仓库,本地仓库用于存放jar包,其实Jar包并不是直接放入工作空间的,它是存放在本地仓库,然后在执行发布打包的时候,添加依赖路径
3 私库:私库是使用者自己搭建的maven仓库,用于缓解频繁从外网下载jar包资源的压力。而且使用私库作为缓存层,也相对安全一些。