Maven基于 项目对象模型(POM) ,是纯 Java 开发的开源项目,可以用于 构建和管理各种项目 。类似工具还有: Ant
、 gradle
。
构件 & 仓库
maven构件
: 在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件。
maven仓库
: 存放项目构件的地方。
构件
在 Maven 中,任何依赖(jar包,tomcat等),或项目(自己打包的jar,war等)输出都可成为构件。每个构件都有自己的唯一标识(唯一坐标),由 groupId
, artifactId
,和 version
三要素 构成。
构件要素 | 说明 |
---|---|
groupId |
必需,当前Maven构件隶属的项目名,一般为 反写的公司公司网址(+项目) 。 |
artifactId |
必需,隶属项目中的模块名,一般为 项目名-模块名 。 |
version |
必需,当前版本。 |
packaging |
默认为 jar ,打包方式:jar, war, ear, pom。 |
version
verison
一般命名格式为 大版本号.分支版本号.小版本号-版本类型
。
版本类型 | 说明 |
---|---|
snapshot |
快照版本 |
alpha |
内部版本 |
beta |
公测版本 |
release |
稳定版本 |
GA |
正式版本 |
packaging
packaging
表示打包种类如 : jar
, war
, ear
。 pom
表示当前 pom 为引用,一般用于父模块,详情如下:
打包方式 | 说明 |
---|---|
jar |
Java Archive file,把开发时要引用通用(JAVA)类及资源做封装,打成包后便于存放管理。 |
war |
Web Archive file,一个(web)完整的应用,通常是网站或WEB平台,打成包部署到容器中。 |
ear |
Enterprise Archive file,企业级应用,实际上EAR包中包含WAR包和几个企业级项目的配置文件而已,服务器中间件通常选择WebSphere等都会使用EAR包。通常是EJB打成ear包。 |
仓库
maven的仓库可以分为 本地仓库
和 远程仓库
两种。
运行 Maven 的时候,Maven 所需要的任何构件都是直接从本地仓库获取的。如果本地仓库没有,它会首先尝试从远程仓库下载构件至本地仓库,然后再使用本地仓库的构件。
本地仓库
Maven在本地存储构件的地方。其在第一次执行maven命令的时才会被创建。
本地仓库的默认位置为用户的目录下 .m2/repository/
。
修改 apache-maven-*\conf\settings.xml
可以更改默认的本地仓库位置。
1 | <settings> |
远程仓库
远程仓库中可以三种:中央仓库
, 私服
, 其它公共库
。
中央仓库
中央仓库包含了绝大多数流行的开源Java构件,以及源码、作者信息、SCM、信息、许可证信息等。一般来说,简单的Java项目依赖的构件都可以在这里下载到。
最核心的中央仓库是默认的远程仓库,maven在安装的时候,所有的maven项目都会继承超级pom,包含了中央仓库的配置,如下:
1 | <repositories> |
私服
私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。我们还可以把一些无法从外部仓库下载到的构件上传到私服上。
当前主流的maven私服:
- Apache 的 Archiva
- JFrog 的 Artifactory
- Sonatype 的 Nexus
其他公共仓库
国外仓库速度较慢,可以国内的镜像仓库,在 settings.xml
的<mirrors></mirrors>
中如下添加即可。
1 | <!-- 使用阿里云的maven镜像仓库(保证速度稳定) --> |
依赖管理
依赖传递
构件具有 依赖传递性 。例如:项目依赖构件A,而构件A又依赖B,Maven会将A和B都视为项目的依赖。
以下依赖范围的构件,不参与传递:
provided
,test
,import
。
解析加载顺序
先 短路优先
,后 声明优先
。
也可以在
pom.xml
中,使用<exclusions></exclusions>
显式排除某个版本的依赖,以确保项目能够运行。
- 短路优先:项目声明依赖构件A和B,构件A → C → D(version:1.0.0),构件B → D(version:1.1.0),此时,Maven会优先解析加载D(version:1.1.0)。
- 声明优先:项目声明依赖构件A和B,构件A → D(version:1.0.0), 构件B → D(version:1.1.0),此时,Maven会优先解析加载D(version:1.0.0)。
依赖范围(scope)
依赖范围(scope) : 编译期,运行期,测试期,分别对应Maven在项目构建过程中编译的三套 classpath 。而依赖范围,就是为构件指定它可以作用于哪套classpath。其可在 <scope></scope>
设置。
依赖范围 | 编译期 | 测试期 | 运行期 | 说明 |
---|---|---|---|---|
compile | ✓ | ✓ | ✓ | 默认范围 |
provided | ✓ | ✓ | 希望运行期由web容器提供依赖, 依赖不可传递 。如servlet-api.jar。 | |
runtime | ✓ | ✓ | 编译期无需直接引用,如jdbc驱动的实现。 | |
test | ✓ | 只在测试目录下才可使用,主目录下回报错, 依赖不可传递 。如设置junit依赖范围。 | ||
system | ✓ | ✓ | 必须通过 <systemPath></systemPath> 元素,显示指定依赖文件的路径,与本地系统相关联,可移植性差。 |
|
import | 导入依赖,它只使用在 dependencyManagement ,表示导入 此依赖pom 中的依赖,作用类似于 parent , 依赖不可传递。 |
聚合 & 继承
聚合
分层架构、分模块开发,可以提高代码的清晰和重用,在父模块使用<modules></modules>
即可聚合多个子模块。 构建父模块时,会自动构建所聚合的子模块。
1 | <modules> |
同时需要 packaging
设置为 pom
。
1 | <packaging>pom</packaging> |
继承
继承就是为了避免重复,maven的继承也是这样,它还有一个好处就是让项目更加安全。 在子模块中使用 <parent></parent>
即可继承父模块属性。
1 | <parent> |
模块化
在模块化开发时,需要同时使用 聚合 和 继承。
父模块
1 | <!-- 将packaging 改为 pom --> |
子模块pom
1 | <parent> |
生命周期
Maven有三个相互独立的标准的生命周期,在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行。
涉及一览 | 说明 |
---|---|
clean | 项目清理的处理。 |
default(build) | 项目部署的处理。 |
site | 项目站点文档创建的处理。 |
Clean
当执行 mvn post-clean
命令时,Maven 调用 clean 生命周期,它包含以下阶段,并有相关命令对应。
mvn clean
就是下面的 clean,在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,mvn clean
等同于mvn pre-clean clean
。
clean生命周期 | 说明 |
---|---|
pre-clean |
执行实际项目清理之前所需的流程。 |
clean |
删除之前构建生成的所有文件, target目录 等。 |
post-clean |
执行完成项目清理所需的流程。 |
Default (Build)
Default 是 Maven 的主要生命周期,被用于构建应用,包括的 23 个阶段,下面为简化的 7 个阶段:
Default简化生命周期 | 说明 |
---|---|
validate |
检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。 |
compile |
编译工程源码,生成 target目录 等。 |
test |
自动运行测试用例并分析(如JUnit)。 |
package |
获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。 |
verify |
运行检查操作来验证工程包是有效的,并满足质量要求。 |
install |
安装工程包到本地仓库中。 |
deploy |
拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。 |
Default 完整生命周期,包括了的 23 个阶段:
Default完整生命周期 | 说明 |
---|---|
validate |
检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。 |
initialize |
初始化构建状态,例如设置属性。 |
generate-sources |
生成编译阶段需要包含的任何源码文件。 |
process-sources |
处理源代码,例如,过滤任何值(filter any value)。 |
generate-resources |
生成工程包中需要包含的资源文件。 |
process-resources |
拷贝和处理资源文件到target目录中,为打包阶段做准备。 |
compile |
编译工程源码。 |
process-classes |
处理编译生成的文件,例如 Java Class 字节码的加强和优化。 |
generate-test-sources |
生成编译阶段需要包含的任何测试源代码。 |
process-test-sources |
处理测试源代码,例如,过滤任何值(filter any values)。 |
test-compile |
编译测试源代码到测试target目录。 |
process-test-classes |
处理测试代码文件编译后生成的文件。 |
test |
使用适当的单元测试框架(例如JUnit)运行测试。 |
prepare-package |
在真正打包之前,为准备打包执行任何必要的操作。 |
package |
获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。 |
pre-integration-test |
在集成测试执行之前,执行所需的操作。例如,设置所需的环境变量。 |
integration-test |
处理和部署必须的工程包到集成测试能够运行的环境中。 |
post-integration-test |
在集成测试被执行后执行必要的操作。例如,清理环境。 |
verify |
运行检查操作来验证工程包是有效的,并满足质量要求。 |
install |
安装工程包到本地仓库中,该仓库可以作为本地其他工程的依赖。 |
deploy |
拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。 |
Site
Maven Site 插件一般用来创建新的报告文档、部署站点等。
site 生命周期 | 说明 |
---|---|
pre-site |
执行一些需要在生成站点文档之前完成的工作。 |
site |
生成项目的站点文档。 |
post-site |
执行一些需要在生成站点文档之后完成的工作,并且为部署做准备。 |
site-deploy |
将生成的站点文档部署到特定的服务器上。 |
POM元素解析
pom.xml
是 maven 项目的配置文件。 因为 pom.xml
内的元素众多,为便于记忆,这里梳理了一些长常见的元素。
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
变量
除了可以在.<properties />
自定义变量,Maven 也提供了一些内置变量。
内置变量 | 说明 |
---|---|
${project.xxx} |
当前pom文件的任意节点的内容。 |
${basedir} |
项目根目录(即 pom.xml 文件所在目录)。 |
${project.build.directory} |
构建目录,缺省为 target 目录。 |
${project.build.outputDirectory} |
构建过程输出目录,缺省为 target/classes 。 |
${project.build.finalName} |
产出物名称,缺省为 ${project.artifactId}-${project.version} 。 |
${project.packaging} |
打包类型,缺省为jar。 |
${env.xxx} |
获取系统环境变量。例如, env.PATH 指代了 $path 环境变量(在Windows上是 %PATH% )。 |
${settings.xxx} |
指代了settings.xml中对应元素的值。例如:<settings><offline>false</offline></settings> 通过 ${settings.offline} 获得offline的值。 |
Java System Properties | 所有可通过 java.lang.System.getProperties() 访问的属性都能在POM中使用,例如 ${JAVA_HOME} 。 |
dependencies
project.dependencies
用于配置项目依赖。
详情参考
依赖管理
。
1 | <dependency> |
resources
project.build.resources
可以自定义项目资源文件的输出位置。
默认行为 & 目录结构
1 | . |
自定义资源文件输出
如下示例,将 src/main/java
下的 *.xml
也有效输出。可以使用 targetPath
指定输出位置,如果只是希望是源目录位置,则不需要。
注意 : 经测试 ,一旦
resource
有效配置 ,原 maven 对resources目录
的默认行为就会失效,所以又添加了如下的配置。
1 | <resources> |
环境隔离
这里是以目录来区分环境, 将通用文件放入 resources
,环境文件放入对应目录,如: resources.dev
和 resources.prod
。使用 activeByDefault
设置启用。
1 | <!-- 配置 profiles ,指定默认为 dev --> |
在打包时也可以指定 profile
,命令优先级高于 xml 配置。
1 | mvn clean package -Dmaven.test.skip=true -P prod |
插件
Maven插件 : maven 的所有工作都是由各种插件完成的,而 maven命令
会控制对应 maven插件
完成相应任务。
maven 自带了一些插件,在 pom.xml
中也可以配置自己需要的插件。
插件类型 | 配置位置 |
---|---|
构建插件 | <build></build> |
报告插件 | <reporting></reporting> |
archetype
Archetype插件 是一个 Maven 项目模板工具包,可以使用其来构建项目。输入以下命令后,会出现原型列表,一般选择 maven-archetype-webapp
即可。
-D
为定义所需参数,也可以直接使用mvn archetype:generate
来构建,maven 会交互式询问所需参数。
1 | 生产 maven 基本骨架 (需要去除换行符) |
默认目录骨架
以下是 maven 的默认目录结构精简版,部分需要自行完善。
手动创建以下目录结构也是可行的。
1 | . |
compiler
Compiler插件 : maven 具有自带的编译插件,即 mvn compiler
所用插件,它有默认值。因为多个项目所需的编译环境可能不同,所以推荐在 pom 中单独配置。
有时可能不会配置这个插件,而是通过修改
本地 maven 配置
或IDE的 maven 配置
来避免错误,但这是不推荐的方式,不利于项目管理。
1 | <!-- compiler:编译插件设置 --> |
如果直接在项目中加入了第三方包,一般会置于 src/main/webapp/WEB-INF/lib
,可以在 <configuration />
中添加如下配置,确保编译正常。
1 | <compilerArguments> |
source
Source插件 可以将源代码进行打包,其中会包含 代码注释
等。
1 | <!-- source:打包源代码插件 --> |
相关常见问题
打包跳过测试
从 build 生命周期可以看出,默认 package
前,一定会执行 test
。可以使用以下命令跳过 :
1 | 推荐 - 不执行测试用例,也不编译测试用例类 |
1 | 不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下 |
snapshot
下载
maven 默认不会下载 snapshot
,可以在 setting.xml
配置如下profile。
1 |
|
deploy
流程
在 setting.xml
中配置私服信息。
1 | <!--对应上传的仓库--> |
在 pom.xml
中配置相应信息。
repository.id
需要与server.id
相同。
1 | <distributionManagement> |
控制台执行
由生命周期可知,
deploy
前会先install
。
1 | mvn deploy -Dmaven.test.skip=true |
安装本地 jar
这里以 Oracle驱动 为例,介绍一下如何将 jar 包到本地仓库。
因为版权问题,一般开源仓库不会拥有 Oracle 的驱动。
首先获取驱动 app\gushi\product\11.2.0\dbhome_1\jdbc\lib\ojdbc6.jar
。命令规则如下:
1 | 安装指定文件到本地仓库命令(需要去除换行符) |
解压 jar 包 可以确驱动版本,如
11.2.0.1.0
。
1 | mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1.0 -Dpackaging=jar -Dfile=ojdbc6.jar |
BUILD SUCCESS
后,即可使用依赖。
1 | <dependency> |