目录
一. 前言
二. Maven 下载与安装
2.1. 下载
2.2. 安装
三. Maven 核心概念
3.1. POM
3.2. 约定的目录结构
3.3. 坐标
3.4. 依赖管理
3.4.1. 直接依赖和间接依赖
3.4.2. 依赖的排除
3.4.3. 统一的版本管理
3.4.4. 依赖范围
3.5. 仓库
3.6. 生命周期/插件/目标
3.6.1. 生命周期
3.6.2. 插件和目标
3.7. 继承
3.8. 聚合
四. Maven 命令
4.1. 常用打包命令
4.2. 命令大全
五. Idea 配置 Maven
Maven 是 Apache 软件基金会组织维护的一款自动化构建工具,专注服务于 Java 平台的项目构建和依赖管理。Maven 这个单词的本意是:专家,内行。读音是['meɪv(ə)n]或['meɪvn]。
下载地址:Maven – Download Apache Maven
下载历史版本:Index of /dist/maven/maven-3
1. 解压maven核心程序安装包,放在一个非中文无空格的文件夹中
2. 配置maven的相关环境变量
新增环境变量名:MAVEN_HOME 或者 M2_HOME。变量值为安装目录bin目录的上一级目录。Maven 1.x版本时,使用MAVEN_HOME,在Maven 2.x版本时我们需要使用M2_HOME,同样现在进入Maven 3.x版本,也延续了Maven 2.x版本,仍然是使用M2_HOME。
Path:%M2_HOME%\bin
运行 mvn -v 命令查看maven的版本。运行命令前确保JDK已配置OK。
Maven 能够实现自动化构建是和它的内部原理分不开的,这里我们从 Maven 的八个核心概念(POM、约定的目录结构、坐标、依赖管理、仓库、生命周期/插件/目标、继承、聚合)入手,看看 Maven 是如何实现自动化构建的。
Pom全称为project object model,意思为项目对象模型。通过xml表示maven项目,使用pom.xml来实现。
主要描述了项目:包括配置文件,开发者需要遵循的规则,组织和项目的url,项目的依赖性,以及其他所有的项目相关因素。
约定的目录结构对于 Maven 实现自动化构建而言是必不可少的一环,就拿自动编译来说,Maven 必须能找到 Java 源文件,下一步才能编译,而编译之后也必须有一个准确的位置保持编译得到的字节码文件。
创建约定的目录结构如下:
helloworld
|----src
|----|----main
|----|----|----java
|----|----|----resources
|----|----test
|----|----|----java
|----|----|----resources
|----pom.xml
1>. helloworld:工程名
2>. src目录:源码
3>. pom.xml文件:Maven工程的核心配置文件
4>. main目录:存放主程序
5>. test目录:存放测试程序
6>. java目录:存放Java源文件
7>. resources目录:存放配置文件
helloworld 项目源码:
// Hello.java
package com.mycom.myapp;
public class Hello {
public String sayHello(String name) {
return "Hello" + name + "!";
}
}
// 测试程序
package com.mycom.test;
import com.mycom.myapp.Hello;
import org.junit.Test;
public class HelloTest {
@Test
public void testHello() {
Hello hello = new Hello();
String result = hello.sayHello("流华追梦");
System.out.println(result);
}
}
// pom.xml
4.0.0
com.mycom.myapp
helloworld
0.0.1-SNAPSHOT
helloworld
junit
junit
4.0
test
1. 几何中的坐标
在一个平面中使用 x、y 两个向量可以唯一的确定平面中的一个点。
在空间中使用 x、y、z 三个向量可以唯一的确定空间中的一个点。
2. Maven 的坐标
使用如下三个向量在 Maven 的仓库中确定一个 Maven 工程:
1>. groupid:定义了项目属于哪个组,举个例子,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp。
2>. artifactId:当前项目的模块名称
3>. version:当前模块的版本
com.mycom.myapp
helloworld
0.0.1-SNAPSHOT
注:SNAPSHOT是快照的意思,代表版本不稳定、尚处于开发中的版本;如果设为Release版本则代表稳定的版本。
3. 如何通过坐标在仓库中查找 jar 包?
1>. 将 gav(groupId、artifactId、version) 三个向量连起来
com.mycom.myapp+helloworld+0.0.1-SNAPSHOT
2>. 用连起来的字符串作为目录结构到仓库中查找
com/mycom/myapp/helloworld/0.0.1-SNAPSHOT/helloworld-0.0.1-SNAPSHOT.jar
3>. 通过网站 https://mvnrepository.com/ 查找jar包坐标以及查看依赖
※注意:我们自己的 Maven 工程必须执行安装操作才会进入仓库。安装的命令是:mvn install
A项目需要引用B项目中的类,那么A对B就产生了依赖,例如:commons-fileupload依赖commons-io包。
Maven解析依赖信息时会到本地仓库中查找被依赖的jar包。对于我们自己开发的Maven工程,使用mvn install 命令安装后就可以进入仓库。
示例:
工程名:hellofriend
目录结构与helloworld工程相同
// pom.xml 文件
4.0.0
com.mycom.myapp
hellofriend
0.0.1-SNAPSHOT
hellofriend
junit
junit
4.0
test
com.mycom.myapp
helloworld
0.0.1-SNAPSHOT
compile
// 主程序,在src/main/java/com/mycom/myapp目录下新建文件HelloFriend.java
package com.mycom.myapp;
import com.mycom.myapp.Hello;
public class HelloFriend {
public String sayHelloToFriend(String name){
Hello hello = new Hello();
String str = hello.sayHello(name) + " I am " + this.getMyName();
System.out.println(str);
return str;
}
public String getMyName(){
return "jek";
}
}
// 测试程序:在/src/test/java/com/mycom/test目录下新建测试文件HelloFriendTest.java
package com.mycom.test;
import org.junit.Test;
import com.mycom.myapp.Hello;
import com.mycom.myapp.HelloFriend;
public class HelloFriendTest {
@Test
public void testHelloFriend(){
HelloFriend helloFriend = new HelloFriend();
String result = helloFriend.sayHelloToFriend("hello!");
System.out.println(result);
}
}
说明:
如果我们想要在工程中引入某个jar 包,只需要在 pom.xml 中引入其 jar 包的坐标即可。比如引入junit的依赖:
junit
junit
4.0
test
Maven 通过 groupId、artifactId与version三个向量来定位 Maven 仓库其 jar 包所在的位置,并把对应的jar 包引入到工程中来。
同理,如果我们想让hellofriend依赖helloworld项目,要在hellofriend添加helloworld的坐标,并把helloworld项目安装在本地仓库。
A依赖B,B依赖于C,A和B之间就是直接依赖;A和C之间就是间接依赖;依赖关系具有传递性。
依赖原则:
1. 路径最短者优先
hellofamily依赖hellofriend,hellofriend依赖helloworld,那么hellofamily将会优先依赖hellofriend中的jar包。
2. 路径相同时先声明者优先
这里“声明”的先后顺序指的是
hellofamily同时依赖 hellofriend(log4j2.jar)和helloworld(log4j2.jar),由于hellofriend先声明,所以会优先使用 hellofriend中的log4j2.jar。
A项目依赖于B项目,B项目中所依赖的jar包是compile范围;B项目中的依赖jar包就可以传递A项目中;
注意:scope定义了依赖的范围,默认是compile,即使不指定默认也是compile。
A项目中如果希望排除掉B项目中传递过来的jar包,可以按照如下配置:
com.mycom.myapp
hellofriend
0.0.1-SNAPSHOT
compile
commons-logging
commons-logging
项目中会对很多第三方框架的jar包进行依赖,同一个框架的jar包版本应该是一致的,如果希望修改框架的版本时,每一个jar包的版本都需要进行改变;如果手动一个一个修改配置依赖,太麻烦;可以设置属性标签,定义jar包的版本,然后通过${}表达式来进行引用。
5.3.7.RELEASE
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
Maven的依赖范围主要是对
依赖范围 | 有效范围(compile, runtime, test) | 依赖传递 | 例子 |
---|---|---|---|
compile | all | 是 | spring-core |
provided | compile, test | 否 | servlet-api |
runtime | runtime, test | 是 | JDBC驱动 |
test | test | 否 | JUnit |
system | compile, test | 是 |
生活中的仓库:仓库由贮存物品的库房、运输传送设施(如吊车、电梯、滑梯等)、出入库房的输送管道和设备以及消防设施、管理用房等组成。是保管、储存物品的建筑物和场所的总称。
Maven中的仓库:主要用来存放第三方jar包,maven所需要的插件已及我们自己开发的maven项目。
仓库分类
本地仓库:在你电脑上存放jar包的位置。例:C:\Users\[登录当前系统的用户名]\.m2\repository。
远程仓库
私服:由公司或单位创建的一个仓库,由公司维护。常用的私服搭建软件有 nexus;
中央仓库:在互联网上,由maven团队维护。常见的中央仓库有:Central Repository:;
中央仓库镜像:中央仓库服务器在外国,中国访问很慢,中央仓库镜像(国内公司提供)就是提高下载速。
什么是镜像:一种文件存储形式,是冗余的一种类型,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。
中央仓库服务器在外国,中国访问很慢,中央仓库镜像(国内公司提供)就是提高下载速度。常用的中央仓库镜像有阿里镜像、腾讯镜像、华为镜像:
aliyun
http://maven.aliyun.com/nexus/content/groups/public/
aliyun
*
aliyun
http://maven.aliyun.com/nexus/content/groups/public/
tencent
http://mirrors.cloud.tencent.com/nexus/repository/maven-public/
tencent
*
tencent
http://mirrors.cloud.tencent.com/nexus/repository/maven-public/
huaweicloud
https://mirrors.huaweicloud.com/repository/maven/
huaweicloud
*
huaweicloud
https://mirrors.huaweicloud.com/repository/maven/
Maven的生命周期就是对所有的构建过程进行统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署等几乎所有的构建步骤。
一个典型的 Maven 构建(build)生命周期是由以下几个阶段的序列组成的:
阶段 | 处理 | 描述 |
---|---|---|
验证 validate | 验证项目 | 验证项目是否正确且所有必须信息是可用的 |
编译 compile | 执行编译 | 源代码编译在此阶段完成 |
测试 Test | 测试 | 使用适当的单元测试框架(例如JUnit)运行测试。 |
包装 package | 打包 | 将编译后的代码打包成可分发的格式,例如 JAR 或 WAR |
检查 verify | 检查 | 对集成测试的结果进行检查,以保证质量达标 |
安装 install | 安装 | 安装打包的项目到本地仓库,以供其他项目使用 |
部署 deploy | 部署 | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程 |
Default (Build) 生命周期:这是 Maven 的主要生命周期,被用于构建应用,包括下面的 23 个阶段:
生命周期阶段 | 描述 |
---|---|
validate(校验) | 校验项目是否正确并且所有必要的信息可以完成项目的构建过程。 |
initialize(初始化) | 初始化构建状态,比如设置属性值。 |
generate-sources(生成源代码) | 生成包含在编译阶段中的任何源代码。 |
process-sources(处理源代码) | 处理源代码,比如说,过滤任意值。 |
generate-resources(生成资源文件) | 生成将会包含在项目包中的资源文件。 |
process-resources (处理资源文件) | 复制和处理资源到目标目录,为打包阶段最好准备。 |
compile(编译) | 编译项目的源代码。 |
process-classes(处理类文件) | 处理编译生成的文件,比如说对Java class文件做字节码改善优化。 |
generate-test-sources(生成测试源代码) | 生成包含在编译阶段中的任何测试源代码。 |
process-test-sources(处理测试源代码) | 处理测试源代码,比如说,过滤任意值。 |
generate-test-resources(生成测试资源文件) | 为测试创建资源文件。 |
process-test-resources(处理测试资源文件) | 复制和处理测试资源到目标目录。 |
test-compile(编译测试源码) | 编译测试源代码到测试目标目录. |
process-test-classes(处理测试类文件) | 处理测试源码编译生成的文件。 |
test(测试) | 使用合适的单元测试框架运行测试(Juint是其中之一)。 |
prepare-package(准备打包) | 在实际打包之前,执行任何的必要的操作为打包做准备。 |
package(打包) | 将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。 |
pre-integration-test(集成测试前) | 在执行集成测试前进行必要的动作。比如说,搭建需要的环境。 |
integration-test(集成测试) | 处理和部署项目到可以运行集成测试环境中。 |
post-integration-test(集成测试后) | 在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。 |
verify (验证) | 运行任意的检查来验证项目包有效且达到质量标准。 |
install(安装) | 安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。 |
deploy(部署) | 将最终的项目包复制到远程仓库中与其他开发者和项目共享。 |
注意:执行任何一个生命周期阶段,之前的生命周期阶段都会被执行。
1. 生命周期与插件是相互绑定的,执行生命周期命令时,需要通过插件来完成。
2. compile和test-compile都通过同一个插件完成的。
3. 目标:就是插件所需要做的事情,例如:maven-compiler-plugin既可以执行compile,也可以执行testCompile, compile和testCompile是maven-compiler-plugin插件的两个功能;当maven-compiler-plugin插件执行compile的时候,那么compile就是插件的一个最终目标。
Maven 提供了下面两种类型的插件:
类型 | 描述 |
---|---|
Build plugins | 在构建时执行,并在 pom.xml 的 元素中配置。 |
Reporting plugins | 在网站生成过程中执行,并在 pom.xml 的 元素中配置。 |
下面是一些常用插件的列表:
插件 | 描述 |
---|---|
clean | 构建之后清理目标文件。删除目标目录。 |
compiler | 编译 Java 源文件。 |
surefile | 运行 JUnit 单元测试。创建测试报告。 |
jar | 从当前工程中构建 JAR 文件。 |
war | 从当前工程中构建 WAR 文件。 |
javadoc | 为工程生成 Javadoc。 |
antrun | 从构建过程的任意一个阶段中运行一个 ant 任务的集合。 |
多个子工程中依赖同样的jar包,但是采用test范围;由于test范围没有传递性;所以,每一个工程都需要对test范围的jar包进行单独依赖;而如果希望修改多个工程中所依赖test范围的jar包版本,那么,一个一个项目去修改太麻烦,这时可以应用继承解决。
继承的使用:
1>. 定义一个父工程,父工程packaging必须是pom。
项目的打包类型:pom、jar、war,packaging默认是jar类型
2>. 在父工程中定义依赖的jar包,属于test范围:
pom
junit
junit
4.0
test
3>. 在各个子工程中对父工程进行继承:
com.mycom.myapp
MavenParent
0.0.1-SNAPSHOT
../MavenParent/pom.xml
4>. 在各个子工程中对父工程中的包进行依赖,但是,不需要配置版本号和范围(与父工程的版本号和范围一致)
junit
junit
5>. 如果希望修改版本,只需要修改父工程中的依赖jar包版本就可以了,那么,各个子工程中的jar包版本就都变了。
6>. 一个子工程只能继承一个父工程。
如果有多个工程需要安装,一个一个工程进行安装,太麻烦了;可以利用聚合,将多个工程管理起来,实现一键安装(也就是将一个父工程进行安装,其他被聚合的工程也同时进行安装)。
../helloworld
../hellofriend
../hellofamily
mvn clean package -Dmaven.test.skip=true -- 跳过测试打包
mvn clean install -Dmaven.test.skip=true -- 跳过测试打包,并把打好的包上传到本地仓库
mvn clean deploy -Dmaven.test.skip=true -- 跳过测试打包,并把打好的包上传到远程仓库
命令 | 含义 |
---|---|
mvn -v | 查看版本 |
mvn archetype:create | 创建 Maven 项目 |
mvn compile | 编译源代码 |
mvn test-compile | 编译测试代码 |
mvn test | 运行应用程序中的单元测试 |
mvn site | 生成项目相关信息的网站 |
mvn package | 依据项目生成 jar 文件 |
mvn install | 在本地 Repository 中安装 jar |
mvn -Dmaven.test.skip=true | 忽略测试文档编译 |
mvn clean | 清除目标目录中的生成结果 |
mvn clean compile | 将.java类编译为.class文件 |
mvn clean package | 进行打包 |
mvn clean test | 执行单元测试 |
mvn clean deploy | 部署到版本仓库 |
mvn clean install | 使其他项目使用这个jar,会安装到maven本地仓库中 |
mvn archetype:generate | 创建项目架构 |
mvn dependency:list | 查看已解析依赖 |
mvn dependency:tree com.xx.xxx | 查看依赖树 |
mvn dependency:analyze | 查看依赖的工具 |
mvn help:system | 从中央仓库下载文件至本地仓库 |
mvn help:active-profiles | 查看当前激活的profiles |
mvn help:all-profiles | 查看所有profiles |
mvn help:effective -pom | 查看完整的pom信息 |