Maven: 是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。
0x01 入门
1.1 maven目录结构
maven3:.
│ LICENSE
│ NOTICE
│ README.txt
│
├─bin //mvn的运行脚本
│ m2.conf
│ mvn
│ mvn.cmd
│ mvnDebug
│ mvnDebug.cmd
│ mvnyjp
│
├─boot //类加载器框架
│ plexus-classworlds-2.5.2.jar
│
├─conf //配置文件
│ │ settings.xml
│ │ toolchains.xml
│ │
│ └─logging
│ simplelogger.properties
│
└─lib //mvn使用的类库
│ aether-api-1.0.2.v20150114.jar
│ aether-api.license
│ aether-connector-basic-1.0.2.v20150114.jar
...
0x02 核心
2.1 maven命令格式
mvn [plugin-name]:[goal-name]:执行“plugin-name”插件的“goal-name”目标(或者称为动作)。
用户调用maven插件目标的两种方式:
- 将插件目标与生命周期阶段(lifecycle phase)绑定,这样用户在命令行只是输入生命周期阶段而已,例如Maven默认将maven-compiler-plugin的compile目标与compile生命周期阶段绑定,因此命令mvn compile实际上是先定位到compile这一生命周期阶段,然后再根据绑定关系调用maven-compiler-plugin的compile目标。
- 直接在命令行指定要执行的插件目标,例如mvnarchetype:generate 就表示调用maven-archetype-plugin的generate目标,这种带冒号的调用方式与生命周期无关。
2.2 maven常用命令
Maven命令列表 | |
---|---|
mvn –version | 显示版本信息 |
mvn clean | 清理项目生产的临时文件,一般是模块下的target目录 |
mvn compile | 编译源代码,一般编译模块下的src/main/java目录 |
mvn package | 项目打包工具,会在模块下的target目录生成jar或war等文件 |
mvn test | 测试命令,或执行src/test/java/下junit的测试用例. |
mvn install | 将打包的jar/war文件复制到你的本地仓库中,供其他模块使用 |
mvn deploy | 将打包的文件发布到远程参考,提供其他人员进行下载依赖 |
mvn site | 生成项目相关信息的网站 |
mvn eclipse:eclipse | 将项目转化为Eclipse项目 |
mvn dependency:tree | 打印出项目的整个依赖树 |
mvn archetype:generate | 创建Maven的普通java项目 |
mvn tomcat:run | 在tomcat容器中运行web应用 |
mvn jetty:run | 调用 Jetty 插件的 Run 目标在 Jetty Servlet 容器中启动 web 应用 |
注意:运行maven命令的时候,首先需要定位到maven项目的目录,也就是项目的pom.xml文件所在的目录。否则,必以通过参数来指定项目的目录。
命令参数
上面列举的只是比较通用的命令,其实很多命令都可以携带参数以执行更精准的任务。
Maven常用命令参数列表 | ||
---|---|---|
-D | 传入属性参数 mvn package -Dmaven.test.skip=true以“-D”开头,将“maven.test.skip”的值设为“true”,就是告诉maven打包的时候跳过单元测试。同理,“mvn deploy-Dmaven.test.skip=true”代表部署项目并跳过单元测试。 |
- -DskipTests=true:编译测试,但不运行 - -Dmaven.test.skip=true:既不编译测试,也不运行。 |
-P | 使用指定的Profile配置 比如项目开发需要有多个环境,一般为开发,测试,预发,正式4个环境,在pom.xml中的配置如下:profiles定义了各个环境的变量id,filters中定义了变量配置文件的地址,其中地址中的环境变量就是上面profile中定义的值,resources中是定义哪些目录下的文件会被配置文件中定义的变量替换。 通过maven可以实现按不同环境进行打包部署,命令为: mvn package -P dev 其中“dev“为环境的变量id,代表使用Id为“dev”的profile。 |
|
-e | 显示maven运行出错的信息 | |
-o | 离线执行命令,即不去远程仓库更新包 | |
-X | 显示maven允许的debug信息 | |
-U | 强制去远程更新snapshot的插件或依赖,默认每天只更新一次 | |
-T | 指定构建中涉及的并行线程数。如果您的项目可以并行地构建,例如不依赖于彼此的模块,则此选项表示-T 4(使用4个线程)可以显着加速您的构建时间。 | |
-pl |
仅构建指定的模块,而不是整个项目。当您在多模块项目的一个模块中工作时,您知道您的更改将在那里本地化,因此您可能希望避免通过建立其他所有内容来完成空的工作。 |
2.3 maven构建项目目录骨架
maven提供的archetype插件,用于创建符合maven规定的目录骨架。 目录规定:src-main-java-主代码 /src-test-java-测试代码
maven 调用archetype命令的两种方式:
mvn archetype:generate<br />
运行命令后根据提示信息依次输入坐标信息(GAV)和包名:groupId,artifactId,version,packagemvn archetype:generate -DgroupId:组织名,公司域名反写+项目名 -DartifactId:项目名-模块名 -Dversion:版本 -Dpackage:包名<br />
一次性创建
data-web:.
│ data-web.iml
│ pom.xml
│ readme
│
├─src
│ ├─main
│ │ ├─java
│ │ │ └─package //自定义的包
│ │ │
│ │ └─resources
│ │
│ └─test
│ └─java
│ └─package //自定义的包
│
└─target
├─classes
│ │ application.properties
│ │ ...
│ │
│ ├─package //编译生成的字节码文件(.class)
│ │ └─...
│ │
│ └─META-INF
│ data-web.kotlin_module
│
├─generated-sources
│ └─annotations
├─generated-test-sources
│ └─test-annotations
└─test-classes
└─package //
2.4 maven生命周期和插件
Maven 构建生命周期定义了一个项目构建跟发布的过程。maven对生命周期的每个阶段进行了抽象,每个插件就是对每个抽象的具体实现。 一个典型的 Maven 构建(build)生命周期是由以下几个阶段的序列组成的:清理、编译、测试、打包、集成测试、验证、部署。
Maven的生命周期分为三个独立的生命周期:
- clean:清理项目
- pre-clean :执行清理前的工作
- clean:清理上一次构建生成的所有文件
- post-clean:执行清理后的文件
- default:构建项目
- compile
- -test
- -package
- -install
- site:生成项目站点
- pre-site:在生成项目站点之前要完成的工作
- site:生成项目的站点文档
- post-site:在生成项目站点后要完成的工作
- site-deploy:发布生成的站点到服务器上
Tips
- 每一个独立的生命周期有分为若干个阶段,其中defaul是最核心的一个;
- Maven的生命周期对应的命令是顺序执行的,如果没有人为的顺序的一个个执行,那么Maven会默认的自动运行;当我们从中间的某个阶段执行了的话,Maven也会自动的为当前阶段执行前面的每个阶段的。
2.5 maven pom.xml解析
2.6 maven依赖范围
Maven因为执行一系列编译、测试和部署运行等操作,在不同的操作下使用的classpath不同,依赖范围就是用来控制依赖与三种 classpath(编译classpath、测试classpath、运行classpath)的关系。
依赖范围(scope):
1.compile:默认范围,使用此依赖范围对于编译、测试、运行三种 classpath 都有效,即在编译、测试和运行的时候都要使用该依赖jar包
2.provided:在编译和测试时有效
3.runtime:在测试和运行时有效, 在编译主代码时无效,典型的就是JDBC驱动实现
4.test:只在测试时有效,典型的是JUnit,它只用于编译测试代码和运行测试代码的时候才需要
5.system:在编译和测试时有效,与本机系统关联,可移植性差必须通过systemPath元素显示地指定依赖文件的路径,不依赖Maven仓库解析,所以可能会造成建构的不可移植,谨慎使用
6.import:导入的范围,它只使用在dependencyManagement中,表示从其他的pom中导入dependency的配置
2.7 maven依赖传递
传递依赖:简单讲就是间接依赖关系,比如:B依赖A,C依赖B,那么C也就依赖A了,C和A的依赖关系就是传递依赖。
Maven对于依赖的管理是这样的,当在POM.XML文件中发现配置了,某个依赖,就先去自己本地的依赖仓库中去找对应的依赖,如果没找到,就去Maven的中央依赖仓库中去找,如果还是没找到,就会报错。
对于项目而言,比如上面的例子A/B/C我们需要在B的POM.XML依赖关系中配置上A的坐标,并且需要对A进行编译、打包、安装到本地仓库等工作,B才能实现对A的依赖。C依赖于B,并且B依赖于A,C的依赖库里会自动的将A项目的jar包也导进来的。如果我们不想这样,那么就需要用到排除依赖这个标签了
2.8 maven依赖冲突
依赖冲突原则:
1.短路优先:C依赖B,B依赖A,A和B都包含同一个不同版本的Jar,则取B的依赖版本
2.声明优先:C依赖A和B,A和B都包含同一个不同版本的Jar,谁先声明取谁的依赖版本
2.9 maven聚合和继承
聚合:
如果项目D依赖项目C,项目C依赖项目B,项目B依赖项目A,我们需要一个个安装这项项目,在Maven中有一种方式可以将多个项目一次性安装,这就是聚合的概念。简单讲就是,需要人工多次操作的,只要Maven能理解,一次性告诉他,他就能帮我们做这件单调烦人的事情了。——使用
继承:
多次使用到的依赖,比如:单元测试,没有必要在所有的项目中都引用一下,此时就可以采用继承的方式来实现,先来一个父级的POM.XML然后再继承此POM.XML。
1. packaging 改为pom。
2. dependencyManagement 中并不提取依赖,只进行统一管理。
3. property中定义了junit版本号,之后可以引用。
4. 父类parent中的main和test没有意义,可以删除。
0x03 实战
0x04 Maven cheat sheet
0x05 Preference
What is Maven
比较 Gradle,Maven和Ant
Maven Options Cheat Sheet
Maven 完整参考