Maven 教程

logo-maven

一、Maven简介

Maven是一个开源的构建工具,它可以帮助我们管理项目的构建过程,管理项目的生命周期,jar包依赖关系等。Maven配合持续集成可以实现自动化的编译、测试、打包、发布等强大的功能,尤其在持续集成上有为我们带来了很大便利。

二、Maven的简单命令及配置

1、首先解压Maven到任意目录:

maven-unzip

2、新建环境变量 M2_HOME,值为 Maven主目录

Maven-M2_HOME

3、在 Path 变量中添加 Maven的bin目录

Maven-Path

4、测试 Maven 是否安装成功

Maven-test

  • 更改Maven 默认仓库地址

默认情况下Mavne 会将jar包插件等下载到 ${user.home}/.m2/repository 下,在Windows 系统下通常是用户目录下的.m2隐藏文件夹,这个文件夹在C盘,我们可以通过更改 Maven的配置文件 M2_HOME/conf/setting.xml 来更改默认的本地仓库位置

Maven-Respository

  • Eclipse中设置maven

在Eclipse中设置使用自己下载的Maven ***Windows->Preferences->Maven->Installations->add ***

Maven-Eclipse-Setting1

然后勾选新添加的 Mavne 并应用设置 在选择 User Setting 设置 配置文件

Maven-Eclipse-Setting2

第一个 Global Setting 为全局设置,一般选择 M2_HOME/conf/setting.xmlUser Setting 是用户设置,一般copy 一份 setting.xml 到任意位置,然后根据自己需要改变一些内容;Maven的配置文件同样遵循”就近原则”;也就是说 User Setting 可以覆盖 Global Setting;如果仅仅自己使用的话,也可以懒一点 两个都选择 M2_HOME/conf/setting.xml,然后只更改 一个配置文件就行了。

三、Maven的使用

  • 在Eclipse中建立Maven项目

首先 New 一个 Maven Project

Maven-create-project

然后直接下一步(让你选择工作空间啥的,默认就行)

Maven-create-project1

选择骨架类型,一般常用的 是 quickstartweb app;骨架的意思是项目的目录结构,maven采用约定优于配置的理念,项目结构已经约定好了,有兴趣可以自己打开工作空间看一下。

Maven-create-project2

填写项目坐标(如果为一个模块,写坐标打包后可被其他项目引用);Artifact ID将作为项目名称。

Maven-create-project3

  • 简单的 jar 包管理

Maven可以很好的为我们管理jar 包中的依赖关系,而我们不必进行像以前一样去下载 jar包,然后添加 class path 这种繁琐的操作,使用Maven后只要我们得知了该jar的仓库坐标,在 POM文件 中添加其坐标后,Maven将自动下载并将其加入 class path 中。假设现在我们需要使用 SpringMVC,首先到 maven仓库 搜索其坐标。

Maven-repository-search

然后打开选择一个版本

Maven-repository-search2

Maven-repository-search3

复制Maven坐标

Maven-repository-search4

将其坐标加入到 POM文件

Maven-repository-search5

稍等片刻,Maven自动下载jar包并加入 classpath

Maven-repository-search6

  • maven的请求下载jar包工作流程如下图所示(有点丑……)

Maven-liucheng

  • Maven的常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#编译命令
#执行此命令 maven将自动编译src/main/java 下的java文件到
#target\classes目录
mvn compile
#测试命令
#执行此命令 maven将自动编译并执行src/test/java 下的java文件
#maven支持JUnit、TestNG等测试框架,@Test注解的方法将自动被执行
#具体可参考 http://seanzhou.iteye.com/blog/1393858
mvn test
#清理命令
#执行此命令将会清空 target目录,清空相关垃圾缓存文件
mvn clean
#打包命令
#执行此命令将对当前项目根据pom文件的描述进行打包
#可打包为 jar、war 等文件格式,便于其他项目使用
mvn package
#安装发布命令
#执行此命令 将自动将项目打包为jar包并根据pom文件内描述坐标
#发布到本地Respoitory中,其他项目可根据其坐标引用
mvn install
#创建骨架
#执行此命令可快速创建maven的项目骨架(文件目录结构和pom文件)
mvn archetype:generate

在 Eclipse 中可右键项目或 POM文件,选择 Run AS 中的 Maven build… 选项手动输入多个命令,Maven将依次执行,截图如下

Maven-RunAs1

Maven-RunAs2

  • 项目模块间的引用

在实际开发中,通常我们将项目分为N多模块进行开发,我们可以使用Maven建立多个项目,然后如果项目模块关联时,比如A模块要调用B模块的方法,我们只需在B项目上运行 mvn cleanmvn install 命令,将其发布到本地仓库,其他模块可根据其坐标直接引入即可。

  • Maven中的隐含变量

在项目多模块的配置时,groupid往往是重复的,某些高级设置时某些位置也可能是重复的,Maven为我们提供了通过变量引用的方式来动态拿到指定值.

Maven提供了三个隐式的变量可以用来访问 环境变量POM信息Maven Settings

  • env变量:

env变量,暴露了你操作系统或者shell的环境变量。如在Maven POM中一个对${env.PATH}的引用将会被${PATH}环境变量替换,在Windows中为%PATH%.

  • project变量

project变量暴露了POM,是使用最多的一个变量,可以使用点标记(.)的路径来引用POM元素的值;如下图

Maven-var1

具体值参考如下(eclipse一般都有提示,没有自行引入maven的dtd文件,此段内容引自 iteye):

1
2
3
4
5
6
7
8
9
10
11
12
#项目根目录
${basedir}
#构建目录,缺省为target
${project.build.directory}
#构建过程输出目录,缺省为target/classes
${project.build.outputDirectory}
#产出物名称,缺省为 ${project.artifactId}-${project.version}
${project.build.finalName}
#打包类型,缺省为jar
${project.packaging}
#当前pom文件的任意节点的内容
${project.xxx}

四、Maven的依赖

每个项目都有其classpath,在Maven管理下的项目实际上有3个classpath(编译classpath测试classpath运行classpath );每个被maven管理的jar包在这三种 classpath 是否生效及如何选择称之为maven的依赖管理,Maven依赖管理可通过 <dependency> 下的 <scope> 标签设置,其值含义如下

1
2
3
4
5
6
7
8
9
10
11
compile: 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。

test: 测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子就是JUnit,它只有在编译测试代码及运行测试的时候才需要。

provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。

runtime: 运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。

system: 系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。systemPath元素可以引用环境变量,如:<systemPath>${java.home}/lib/rt.jar</systemPath>

import(Maven 2.0.9及以上): 导入依赖范围。该依赖范围不会对三种classpath产生实际的影响

例如我们设置JUint,只有测试时用到,scope 只需设置成 test即可

Maven-scope1

  • Maven依赖传递性

当A项目依赖某一jar包,比如log4j 时,将其发布到本地仓库后,B项目进行引用时,则同样会依赖log4j;这种情况称之为 Maven的依赖传递 ,当 scope 设置为 test 时,则依赖不会被传递。

  • Maven复杂依赖

单项目依赖多模块,多模块中jar包版本冲突,如下图

Maven-yilai1

在此种情况下,Maven无法自动判断jar包x的版本;模块C中的jar包x版本取决于C模块的pom文件中 模块A、B的书写位置,也就是说谁先写在上面,那么就先使用谁的,如下

Maven-yilai2

单项目依赖多模块,多模块中jar包版本冲突,但单项目(模块C)中jar包x版本却并非取决于书写顺序,情况如下图

Maven-yilai21

假设模块C的pom文件中仍是先写得模块A;但此时在 模块C中 jar包x的版本仍是2.0;原因是模块A依赖了jar包K,而jar包K又依赖了jar包x;相当于jar包x到模块C之间存在二级关系,此时Maven的依赖选择以最近的为主,如果距离(层级)相同,那么再根据书写顺序判定选择那个,否则优先选择距离(层级)最近的,在Eclipse中可通过视图查看依赖层级关系,如下

Maven-yilai3

  • Maven依赖的排除

当项目模块中存在jar包冲突时,或想使用某个模块中指定的jar包版本,我们可以使用标签进行排除某个jar包,如下

Maven-yilai4

五、Maven的聚合与继承

  • Maven的聚合

我们已经知道Maven中多模块(项目)是可以互相引用的,但在实际开发中往往会遇到一些问题;当模块足够多时,每一次编译打包也就意味着我们要在N多个模块(项目)上执行 clean 、package 等命令,这显然是不能接受的;Maven为我们提供了项目(模块)的聚合功能,也就是说模块最终要统一到一个项目,每次打包编译,我们只需对 “总项目” 进行即可,而无需关心各个模块

1、首先我们创建一个没有骨架的项目(new 一个Maven项目),在下面这步注意要勾选 “跳过骨架选择”

Maven-juhe3

2、填入相关信息,注意打包形式选择pom

Maven-juhe4

3、创建好项目以后我们编辑pom文件,使用标签指定该项目聚合哪些项目(模块)
标签使用相对路径,指向其他项目(模块),一般都是 ../xxxx

Maven-juhe5

4、此时对聚合项目执行一下 clean compile 测试一下,控制台打印如下,可以看出,Maven依次对3个项目执行了相关操作

Maven-juhe6

  • Maven的集成

当成功聚合了多个模块以后,我们还会发现在每个项目模块中存在大量的相同代码,这让我们感觉很不爽;有点 “造轮子” 的嫌疑,当然Maven同样支持继承的操作,也就是说将模块中的相同代码放到父类项目(模块)中,其他模块只需继承即可使用,同时也能很好地解决jar包版本冲突问题

1、首先看一下 各个模块的pom文件,这里面很多都是重复的

Maven-juhe1

Maven-juhe2

2、我们同样新建一个Maven项目,跳过骨架创建

Maven-extends

3、然后我们提取其他子模块pom文件中的共有部分放入父pom文件中(以下为父pom文件),包括共有的定义以及每个项目的依赖jar包(依赖的jar包需要使用 <dependencyManagement> 标签来管理)

Maven-extends1

4、此时我们可以在子项目模块中通过标签指定继承的Pom文件

注意:聚合 <module> 标签指定的是相对的项目,而继承指定的则是相对的pom文件

Maven-extends2

5、当继承后我们便可以删除公有的相同内容,如等;同时依赖的jar包也可不必指定版本

Maven-extends3

6、到此,继承完成,由于依赖jar包都来自父pom,同时子pom依赖的jar包无需书写版本,这样在一定程度上保证了jar包版本的统一性;同时我们可以发现,聚合和继承十分相似,其实我们可以将聚合也加入到这个pom中来,实现一个项目对多个项目(模块)的继承与聚合,如下为示例的pom文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.mritd.Test1</groupId>
<artifactId>MavenParent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>

<modules>
<module>../MavenTest1</module>
<module>../MavenTest2</module>
<module>../MavenTest3</module>
</modules>

<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
</dependencyManagement>

</project>

Maven 教程
https://mritd.com/2015/12/31/maven-tutorial/
作者
Kovacs
发布于
2015年12月31日
许可协议