Maven是Java项目不可缺少的工具,用于项目管理和构建工具。
介绍
Java项目首先需要依赖包的管理,确定引入哪些依赖包,把相关的jar包都放到classpath中。
其次,我们要确定项目的目录结构。例如,src
目录存放Java源码,resources
目录存放配置文件,bin
目录存放编译生成的.class
文件。
第三,需要配置环境,例如JDK的版本,编译打包的流程,当前代码的版本号。
最后,除了使用Eclipse这样的IDE进行编译外,我们还必须能通过命令行工具进行编译,才能够让项目在一个独立的服务器上编译、测试、部署。
Maven就是是专门为Java项目打造的管理和构建工具,它的主要功能有:
- 提供了一套标准化的项目结构;
- 提供了一套标准化的构建流程(编译,测试,打包,发布……);
- 提供了一套依赖管理机制。
Maven项目结构
一个使用Maven管理的普通的Java项目,它的目录结构默认如下:
1 | a-maven-project |
根目录a-maven-project
是项目名,项目描述文件pom.xml
,存放Java源码的目录是src/main/java
,存放资源文件的目录是src/main/resources
,存放测试源码的目录是src/test/java
,存放测试资源的目录是src/test/resources
,最后,所有编译、打包生成的文件都放在target
目录里。
项目描述文件pom.xml
内容:
1 | <project ...> |
其中,groupId
类似于Java的包名,通常是公司或组织名称,artifactId
类似于Java的类名,通常是项目名称,再加上version
,一个Maven工程就是由groupId
,artifactId
和version
作为唯一标识。
引用其他第三方库的时候,也是通过这3个变量确定。例如,依赖commons-logging
:
1 | <dependency> |
使用<dependency>
声明一个依赖后,Maven就会自动下载这个依赖包并把它放到classpath中。
安装Maven
Maven官网下载,本地解压,设置环境变量:
1 | M2_HOME=/path/to/maven-3.6.x |
Windows把%M2_HOME%\bin
添加到系统Path变量中。
小结
Maven是一个Java项目的管理和构建工具:
- Maven使用
pom.xml
定义项目内容,并使用预设的目录结构; - 在Maven中声明一个依赖项可以自动下载并导入classpath;
- Maven使用
groupId
,artifactId
和version
唯一定位一个依赖。
依赖管理
Maven解决了依赖管理问题。例如,我们的项目依赖abc
这个jar包,而abc
又依赖xyz
这个jar包:
1 | ┌──────────────┐ |
当我们声明了abc
的依赖时,Maven自动把abc
和xyz
都加入了项目依赖。
依赖关系
Maven定义了几种依赖关系,分别是compile
、test
、runtime
和provided
:
scope | 说明 | 示例 |
---|---|---|
compile | 编译时需要用到该jar包(默认) | commons-logging |
test | 编译Test时需要用到该jar包 | junit |
runtime | 编译时不需要,但运行时需要用到 | mysql |
provided | 编译时需要用到,但运行时由JDK或某个服务器提供 | servlet-api |
其中,默认的compile
是最常用的,Maven会把这种类型的依赖直接放入classpath。
test
依赖表示仅在测试时使用,正常运行时并不需要。最常用的test
依赖就是JUnit:
1 | <dependency> |
runtime
依赖表示编译时不需要,但运行时需要。最典型的runtime
依赖是JDBC驱动,例如MySQL驱动:
1 | <dependency> |
provided
依赖表示编译时需要,但运行时不需要。最典型的provided
依赖是Servlet API,编译的时候需要,但是运行时,Servlet服务器内置了相关的jar,所以运行期不需要:
1 | <dependency> |
Maven维护了一个中央仓库(repo1.maven.org),所有第三方库将自身的jar以及相关信息上传至中央仓库,Maven就可以从中央仓库把所需依赖下载到本地。
Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过,就会被Maven自动缓存在本地目录(用户主目录的.m2
目录),所以,除了第一次编译时因为下载需要时间会比较慢,后续过程因为有本地缓存,并不会重复下载相同的jar包。
构建流程
Maven有一套标准化的构建流程,可以自动化实现编译,打包,发布。
Lifecycle和Phase
使用Maven时,我们首先要了解什么是Maven的生命周期(lifecycle)。
Maven的生命周期由一系列阶段(phase)构成,以内置的生命周期default
为例,它包含以下phase:
- validate
- initialize
- generate-sources
- process-sources
- generate-resources
- process-resources
- compile
- process-classes
- generate-test-sources
- process-test-sources
- generate-test-resources
- process-test-resources
- test-compile
- process-test-classes
- test
- prepare-package
- package
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install
- deploy
如果我们运行mvn package
,Maven就会执行default
生命周期,它会从开始一直运行到package
这个phase为止:
- validate
- …
- package
如果我们运行mvn compile
,Maven也会执行default
生命周期,但这次它只会运行到compile
,即以下几个phase:
- validate
- …
- compile
Maven另一个常用的生命周期是clean
,它会执行3个phase:
- pre-clean
- clean (注意这个clean不是lifecycle而是phase)
- post-clean
经常使用的命令有:
mvn clean
:清理所有生成的class和jar;
mvn clean compile
:先清理,再执行到compile
;
mvn clean test
:先清理,再执行到test
,因为执行test
前必须执行compile
,所以这里不必指定compile
;
mvn clean package
:先清理,再执行到package
。
经常用到的phase其实只有几个:
clean:清理
compile:编译
test:运行测试
package:打包
lifecycle相当于Java的package,它包含一个或多个phase;
phase相当于Java的class,它包含一个或多个goal;
goal相当于class的method,它其实才是真正干活的。
大多数情况,我们只要指定phase,就默认执行这些phase默认绑定的goal,只有少数情况,我们可以直接指定运行一个goal,例如,启动Tomcat服务器:
1 | mvn tomcat:run |
小结
Maven通过lifecycle、phase和goal来提供标准的构建流程。
最常用的构建命令是指定phase,然后让Maven执行到指定的phase:
- mvn clean
- mvn clean compile
- mvn clean test
- mvn clean package
通常情况,我们总是执行phase默认绑定的goal,因此不必指定goal。
使用插件
Maven已经内置了一些常用的标准插件:
插件名称 | 对应执行的phase |
---|---|
clean | clean |
compiler | compile |
surefire | test |
jar | package |
如果标准插件无法满足需求,我们还可以使用自定义插件。使用自定义插件的时候,需要声明。例如,使用maven-shade-plugin
可以创建一个可执行的jar,要使用这个插件,需要在pom.xml
中声明它:
1 | <project> |
自定义插件往往需要一些配置,例如,maven-shade-plugin
需要指定Java程序的入口,它的配置是:
1 | <configuration> |
注意,Maven自带的标准插件例如compiler
是无需声明的,只有引入其它的插件才需要声明。
下面列举了一些常用的插件:
- maven-shade-plugin:打包所有依赖包并生成可执行jar;
- cobertura-maven-plugin:生成单元测试覆盖率报告;
- findbugs-maven-plugin:对Java源码进行静态分析以找出潜在问题。
小结
Maven通过自定义插件可以执行项目构建时需要的额外功能,使用自定义插件必须在pom.xml中声明插件及配置;
插件会在某个phase被执行时执行;
插件的配置和用法需参考插件的官方文档。
模块管理
对于Maven工程来说,原来是一个大项目:
1 | single-project |
现在可以分拆成3个模块:
1 | single-project |
Maven可以有效地管理多个模块,我们只需要把每个模块当作一个独立的Maven项目,它们有各自独立的pom.xml。
模块A和模块B的pom.xml高度相似,因此,我们可以提取出共同部分作为parent,编写parent的pom.xml只是为了在各个模块中减少重复的配置。现在整个工程结构如下:
1 | single-project |
不推荐把自己的模块安装到maven的本地仓库,因为每次修改模块b的源码,都需要重新安装, 容易出现版本不一致的情况
推荐的做法是模块化编译,在编译的时候,告诉maven几个模块之间存在依赖关系,需要一块编译, maven就会自动按依赖顺序编译这些模块
1 | <modules> |
使用mvnw
mvnw
是Maven Wrapper的缩写,Maven Wrapper就是给一个项目提供一个独立的,指定版本的Maven给它使用。
安装Maven Wrapper
安装Maven Wrapper最简单的方式是在项目的根目录(即pom.xml
所在的目录)下运行安装命令:
1 | mvn -N io.takari:maven:0.7.6:wrapper |
如果要指定使用的Maven版本,使用下面的安装命令指定版本,例如3.3.3
:
1 | mvn -N io.takari:maven:0.7.6:wrapper -Dmaven=3.3.3 |
安装后,查看项目结构:
1 | my-project |
发现多了mvnw
、mvnw.cmd
和.mvn
目录,只需要把mvn
命令改成mvnw
就可以使用跟项目关联的Maven。
例如:
1 | mvnw clean package |
在Linux或macOS下运行时需要加上./
:
1 | ./mvnw clean package |
Maven Wrapper的另一个作用是把项目的mvnw
、mvnw.cmd
和.mvn
提交到版本库中,可以使所有开发人员使用统一的Maven版本。
发布时间: 2019-12-14
最后更新: 2019-12-14
本文链接: https://juoyo.github.io/posts/54cd077b.html
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!