Maven

Maven 是一个项目管理和构建自动化工具,它包含了一个项目对象模型,一组标准集合,一个项目生命周期,一个依赖管理系统,和用来运行定义在生命周期阶段中插件目标的逻辑。
使用Maven创建项目后,文件目录如下:

目录 目的
${basedir} 存放 pom.xml和所有的子目录
${basedir}/src/main/java 项目的 java源代码
${basedir}/src/main/resources 项目的资源,比如说 property文件
${basedir}/src/test/java 项目的测试类,比如说 JUnit代码
${basedir}/src/test/resources 测试使用的资源

Maven中重要的一个文件是pom文件,上面是一个简单的pom文件:其中groupId, artifactId, packaging, version 叫作 Maven 坐标,它能唯一的确定一个项目。有了Maven 坐标,我们就可以用它来指定我们的项目所依赖的其他项目,插件,或者父项目。在复杂的项目中,大项目一般会分成几个子项目。在这种情况下,每个子项目就会有自己的 POM 文件,然后它们会有一个共同的父项目。这样只要构建父项目就能够构建所有的子项目了,子项目的 POM 会继承父项目的 POM。
下面我们从Maven库,生命周期,依赖库来对Maven进行介绍:

Maven库

Maven库分本地库、中央存储库、远程存储库。其中,本地库指 Maven 下载了插件或者 jar 文件后存放在本地机器上的拷贝。在 Linux,mac os 上,它的位置在 ~/.m2/repository,在 Windows XP 上,在 C:\Documents and Settings\username.m2\repository ,在 Windows 上,在 C:\Users\username.m2\repository,我们可以修改setting.xml中localRepository结点来改变本地库的位置。当你建立一个 Maven 的项目,Maven 会检查你的 pom.xml 文件,以确定哪些依赖下载。首先,Maven 将从本地资源库获得 Maven 的本地资源库依赖资源,如果没有找到,然后把它会从默认的 Maven 中央存储库 – http://repo1.maven.org/maven2/ 查找下载。在Maven中,当你声明的库不存在于本地存储库中,也没有不存在于Maven中心储存库,可以设置从远程存储库中搜索,设置的方式如下,会从Java.net中搜索需要的Jar:
所以Maven的依赖库查询顺序为:
(1)在 Maven 本地资源库中搜索,如果没有找到,进入第 2 步,否则退出。
(2)在 Maven 中央存储库搜索,如果没有找到,进入第 3 步,否则退出。
(3)在Java.net Maven的远程存储库搜索,如果没有找到,提示错误信息,否则退出。

Maven 生命周期

Maven的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。Maven有三套相互独立的生命周期,分别是clean、default和site。每个生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面。

1.clean生命周期:清理项目,包含三个phase。
1)pre-clean:执行清理前需要完成的工作
2)clean:清理上一次构建生成的文件
3)post-clean:执行清理后需要完成的工作

2.default(build)生命周期:构建项目,重要的phase如下。
1)validate:验证工程是否正确,所有需要的资源是否可用。
2)compile:编译项目的源代码。
3)test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。
4)Package:把已编译的代码打包成可发布的格式,比如jar。
5)integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。
6)verify:运行所有检查,验证包是否有效且达到质量标准。
7)install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。
8)Deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。

3.site生命周期:建立和发布项目站点,phase如下
1)pre-site:生成项目站点之前需要完成的工作
2)site:生成项目站点文档
3)post-site:生成项目站点之后需要完成的工作
4)site-deploy:将项目站点发布到服务器

各个生命周期相互独立,一个生命周期的阶段前后依赖,如mvn clean install,调用clean生命周期的clean阶段和default的install阶段,实际执行pre-clean和clean,install以及之前所有阶段。Maven插件目标可以绑定到生命周期阶段上。一个生命周期阶段可以绑定多个插件目标。当 maven 在构建过程中逐步的通过每个阶段时,会执行该阶段所有的插件目标。

Maven依赖管理

依赖是使用Maven坐标来定位的,而Maven坐标主要groupId, artifactId,version构成,随着项目的增大,依赖越来越多,兼容性和冲突问题将会出现,maven通过依赖范围和传递性依赖以及排除依赖来管理依赖问题。下面是一个简单的依赖配置文件:

1
2
3
4
5
6
7
8
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>

Maven不但下载了 junit-3.8.1.jar,还下载了它的 POM 文件。这样 Maven 就能检查Junit 的依赖关系,把它所需要的依赖也包括进来。依赖的主要几个元素如下:
groupId,artifactId和version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖
type: 依赖的类型,对应于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值是jar
scope: 依赖的范围
optional: 标记依赖是否可选
exclusions: 用来排除传递性依赖
scope指依赖范围,主要有compile、test、provided、runtime、system这几类,是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系,它们的范围如下:
compile: 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行
test: 测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效
provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。
runtime: 运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
system: 系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过systemPath元素显式地指定依赖文件的路径。

当我们引入第三方Jar包的时候,难免会引入传递性依赖,有些时候这是好事,然而有些时候我们不需要其中的一些传递性依赖,可以在们可以使用exclusions元素声明排除依赖,exclusions可以包含一个或者多个exclusion子元素,因此可以排除一个或者多个传递性依赖。需要注意的是,声明exclusions的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖,不会出现重复。
当同一个模块,所依赖的几个模块版本都相同时,可以使用maven里的属性做分类依赖,依赖版本升级时改一处即可,如Spring Framework的依赖,可以使用 如下方式:

1
2
3
<properties>
<springframework.version>2.5.6</springframework.version>
</properties>

然后在dependency中使用这个版本即可。

谢谢大佬的打赏!