引:使用Java语言来开发你的项目,基本上都少不了Maven,因为有了它真是太方便了!
什么是Maven
Maven是一种用来管理Java项目的工具、但不是那种那种用来管理资源规划和调度的工具。相反,它处理的时一个具体的项目所涉及的各种任务,如编译、测试、打包以及部署。
Maven包括以下几个部分:
一组用于处理管理依赖(从中央仓库拉取的jar包)、目录结构以及构建工作流的约定。
基于这些约定实现的标准化可以极大地简化开发过程。例如,一个常用的目录结构使得开发者可以更加容易跟上不熟悉的项目的节奏。
一个用于项目配置的XML Schema:项目对象模型(Project Object Model),简称POM。
每一个Maven项目都拥有一个POM文件,并命名为pom.xml,包含Maven用于管理该项目的所有的配置信息。
一个委托外部组件来执行项目任务的插件结构。
这简化了更新一集扩展Maven能力的过程。
Maven安装
PS: 上面提到了Maven帮我们管理依赖,是通过从中央仓库拉取jar包(依赖)来实现,但是由于Maven的中央仓库在国外,拉取会比较慢,所以我们一般会通过配置阿里云镜像来加快速度,当然你也可以Nexus搭建自己的私有仓库。
POM
POM文件大纲如下:1
2
3
4
5
6
7
8
9
10<project> // 根元素
<groupId/>
<artifactId/>
<version/> // 上面三个(GAV坐标)唯一地定义Maven项目的值
<packaging/> // 项目打包方式,默认值是jar
<properties/> // 在POM中引用的属性,一般会放版本信息
<dependencies/> //构建当前项目所需要的其他Maven项目
<build/> // 构建改项目所需要执行的任务的配置
<profiles/> // 为不同的用例自定义POM,一般用来配置环境的切换
</project>
Maven构件
任何可以被Maven的坐标系统(GAV)唯一标识的对象都是一个Maven构件。
Maven构件的类型由pom文件的
POM文件使用方式
- 默认的:用于构建一个构件
- 父POM:提供一个由子项目继承的单个配置信息源,子项目通过声明这个pom文件作为它们的
元素值 - 聚合器:用于构建一组声明为
的项目,这些子项目位于其当前聚合器项目的文件夹中,每个都包含有他自己的pom文件
PS: 作为父pom或者聚合器的pom文件的
GAV坐标
POM定义了5种称为坐标的元素,用于标识Maven构件,首字母缩写GAV指的是必须始终指定的3个坐标
下面的坐标是按照他们在坐标表达式中出现的顺序列出:
是项目或者项目组的全局唯一标识符。这通常是Java源代码使员工的全限定的Java包名。例如,io.netty、com.google。 用于标识和某个 相关的不同的构件。例如,netty-all、netty-handler。 是指和项目相关的主要构件的类型(对应于构件的POM文件中的 值)。它的默认值是jar,此外还有pom、ear。 标识了构件的版本、例如1.1、2.0-SNAPSHOT、4.1.9.Final。 用于区分属于相同的POM但是却被以不同方式构建的构件。例如,javadock、sources、jdk16、jdk17。
一个完整的坐标表达式具有如下格式:1
actifactId:groupId:packaging:version:classifier
POM文件必须声明它所管理的构件的坐标,一个具有如下坐标的项目:1
2
3
4<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.9.Final</version>
<packaging>jar</packaging>
将会产生一个具有以下格式的名称的构件:artifactId-<version>.<packaging>
依赖
依赖引入
项目的依赖是指编译和执行它所需要的外部构件。在大多数情况下,你的项目的依赖项也会有它自己的依赖。我们称这些依赖为你的项目的传递依赖。一个负责的项目可能会有一个深层级的依赖树。Maven 提供了各种用于帮助理解和管理它的工具,如执行mvn dependency:tree
。
Maven的1
2
3
4
5
6
7
8
9
10<dependencies>
<dependency>
<groupId/>
<artifactId/>
<version/>
<type/>
<scope/>
<systemPath/>
</dependency>
</dependencies>
在
关于scope指的是依赖范围,即classpath,Maven里有3类依赖范围:
- 编译
- 测试
- 运行
- compile:编译(默认)
- runtime:运行
- provided:对于编译和测试有效,运行时无效
- test:测试
- import:使用在
中,导入其他项目的 - systemPath:与provided一直,但是需要指定依赖文件的绝对位置
依赖管理
POM的
引用了
最佳实践:在原POM中的所有版本都利用
构件的生命周期
Maven的生命周期就是为了对所有的构建过程进行抽象和统一。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。也就是说,几所所有的项目的构建,都能映射到这样一个生命周期上。
Maven拥有三套相互独立生命周期,他们分别为clean、default和site。clean生命周期的目的是清理项目、default生命周期的目的是构建项目、site生命周期的目的是建立项目站点。每个生命周期包含一些阶段,这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段。但是三套生命周期本身是相互独立的。我们按照日常的需求,我们只说前两个。
clean生命周期
它包含三个阶段:
- pre-clean:执行清理前要完成的工作。
- clean:清理上一次构建生成的文件。
- post-clean:执行一些清理后需要完成的工作。
default生命周期
default生命周期定义了真正构建时所需要执行的而所有步骤,这里也只是列出重要的阶段:
- validate:检查项目是否正确
- compile:编译项目的源代码
- test:使用单元测试框架进行测试,测试代码不会被打包部署
- package:将编译的代码打包为可发布的格式,如jar
- verify:验证软件包是否有效
- install:将包安装到本地仓库中,可以供本地其他Maven项目使用
- deploy:将包复制到远程仓库中,可以供其他开发人员使用
插件
虽然Maven协调了所有构建生命周期阶段的执行,但是他并没有直接实现它们,而是将他们委托给了插件。这些插件是maven-plugin类型的构件(打包为JAR文件)。Maven为标准构件生命周期所定义的所有任务都提供了插件,但更多的是由第三方生产的,用于处理各种自定义的任务。
插件目标
每个插件都有很多功能,每个插件功能对应了插件一个目标。如我们之前分析依赖的maven-dependency-plugin,它就有十多个目标,如下:1
2
3
4// 命令行冒号前面是插件,冒号后面是目标(功能)
mvn dependency:analyze
mvn dependency:tree
mvn dependency:list
插件绑定
Maven的生命周期与插件相互绑定,用以完成实际的构建任务。
内置绑定
为了让用户几乎不用任何配置就能构建Maven项目,Maven为一些主要的生命周期阶段绑定了很多插件的目标,如:
- maven-clean-plugin:clean绑定了clean
- maven-compiler-plugin:compile绑定了compile
- maven-surefire-plugin:test绑定了test
- maven-jar-plugin:jar绑定package默认
- maven-install-plugin:install绑定了install
自定义绑定
除了内置绑定之外,用户还能够自己选择将某个插件目标绑定到生命周期的某个阶段上。如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<build>
<plugins>
<plugin>
<!--引入插件-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<!--构建任务-->
<executions>
<execution>
<id>attach-source</id>
<!--绑定阶段-->
<phase>verify</phase>
<!--绑定目标-->
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
很多插件的目标在编写是就已经定义了默认绑定阶段,可以利用maven-help-plugin查看插件详细信息,了解插件目标的默认绑定阶段。运行命令如下:1
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:3.0.1
如果多个目标被绑定到同一个阶段的时候,这些插件声明的先后顺序决定了目标的执行顺序。
插件配置
命令行插件配置
很多插件目标的参数都是支持命令行配置的,用户可以在Maven命令中使用-D参数,并伴随参数键=参数值的形式来配置插件目标的参数,如上mvn help
。
POM中插件全局配置
为了避免插件参数重复书写,我们可以在pom进行全局配置,如下:1
2
3
4
5
6
7
8
9
10
11<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<!--编译Java1.8版本的源文件-->
<source>1.8</source>
<!--生成与JVM1.8兼容的字节码文件-->
<target>1.8</target>
</configuration>
</plugin>
插件管理
POM的
引用了
最佳实践:在原POM中的所有版本都利用
聚合和继承
聚合
如果我们想要一次构建两个项目,而不是到两个模块的目录下分别执行mvn命令,那么我们可以使用Maven聚合。
我们先创建一个聚合构件(除了pom文件(packaging需要为pom),其他可以都不要),然后在聚合构件目录下创建两个构件,并在聚合构件下利用1
2
3
4<modules>
<module>email</module>
<module>user</module>
</modules>
继承
如果两个项目有重复的依赖或插件,我们可以使用继承。
我们先创建一个父构件(除了pom文件(packaging需要为pom),其他可以都不要),然后在父构件目录下创建两个子构件,并在子构件下利用1
2
3
4
5
6<parent>
<groupId/>
<artifactId/>
<version/>
<relativePath>父pom的相对路径</relativePath>
</parent>