Maven⯐
常规开发生命周期
阶段 | 主要工作 |
---|---|
依赖管理 | 收集依赖构件到CLASSPATH,手动下载依赖库繁琐且易出错 |
编码 | 编写源代码、配置信息 |
构建 | JavaC编译 |
测试 | 单元测试 |
打包、发布 | 手动构建发布属于重复性工作 |
共享 | 代码共享、储存,以及版本控制 |
简介
-
Maven介绍、安装、常用命令
-
Eclipse下Maven项目开发
-
坐标与依赖
-
多模型开发
-
常用插件和自动化部署
-
内部仓库使用
-
生成站点
-
Maven高级主题
Maven介绍
Maven是一个项目管理工具,它包含了一项目对象模型(Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Manangement System),和用来运行定义在生命周期阶段中插件目标的逻辑。
Maven 能够帮助开发者完成以下工作:
-
构建
-
文档生成
-
报告
-
依赖
-
SCMs
-
发布
-
分发
-
邮件列表
Maven概念模型
约定优于配置
Maven 使用约定而不是配置,意味着开发者不需要再自己创建构建过程。
Maven 为工程提供了合理的默认行为。当创建 Maven 工程时,Maven 会创建默认的工程结构。开发者只需要合理的放置文件,而在 pom.xml 中不再需要定义任何配置。
配置项 | 默认值 |
---|---|
source code | ${basedir}/src/main/java |
resources | ${basedir}/src/main/resources |
Tests | ${basedir}/src/test |
Complied byte code | ${basedir}/target |
distributable JAR | ${basedir}/target/classes |
Maven名词解释
任何您想build的事物,Maven都可以认为它们是工程。这些工程被定义为工程对象模型(POM,Poject Object Model)。一个工程可以依赖其它的工程;一个工程也可以由多个子工程构成。
POM(pom.xml)是Maven的核心文件,它是指示Maven如何工作的元数据文件,类似于Ant中的build.xml文件。
groupId是一个工程的在全局中唯一的标识符,一般地,它就是工程名。groupId有利于使用一个完全的包名,将一个工程从其它有类似名称的工程里区别出来。
artifact 是工程将要产生或需要使用的文件,它可以是jar文件,源文件,二进制文件,war文件,甚至是pom文件。每个artifact都由groupId和 artifactId组合的标识符唯一识别。需要被依赖的artifact都要放在仓库(见Repository)中,否则Maven无法识别它们。
为了能够build或运行,一个典型的Java工程会依赖其它的包。在Maven中,这些被依赖的包就被称为dependency。dependency一般是其它工程的artifact。
Maven是由插件组织的,它的每一个功能都是由插件提供的。插件提供goal(类似于Ant中的target),并根据在POM中找到的元数据去完成工作。
仓库。
setting.xml
-
$user.home/.m2/repository/setting.xml
- 为用户范围的配置文件
-
$M2_HOME/conf/setting.xml
-
为全局范围的配置文件,修改后将影响本机所有用户的配置
- 建议:只修改用户级别的配置,既不影响其它用户,也不影响后期升级。
-
配置介绍
-
localRepository: 自定义本地库路径,默认在$user.home/.m2中
-
interactiveMode:
-
offline:是否每次编译都去查找远程中心库
-
pluginGroups:插件组,例如org.mortbay.jetty
-
proxies:通过代理访问外部库
-
servers:集成认证服务,例如集成Tomcat
-
mirrors:镜像库,可以指定内部中心库
-
profiles:个性配置,需要在Activation标签中激活
-
activeProfiles:表示激活的profile
-
Maven仓库
https://repo1.maven.org/maven2
这个公共仓库是由Maven自己维护,里面有大量的常用类库,并包含了世界上大部分流行的开源项目构件。目前是以java为主。
也称私有共享仓库(私服)。一般是由公司自己设立的,只为本公司内部共享使用。它既可以作为公司内部构件协作和存档,也可作为公用类库镜像缓存,减少在外部访问和下载的频率。
Nexus和Artifactory均可搭建仓库服务器。但后者支持LDAP认证,这样就可以将私有仓库的认证集成到公司已经有的LDAP认证服务器。
内部中心库又可以连接第三方库,例如Jboss中心库、Spring中心库,以随时获得最新版本的第三方构件。
Maven会将工程中依赖的构件(Jar包)从远程下载到本机一个目录下管理,通常默认在$user.home/.m2/repository下。
自Maven2以后,构件的存储方式通常是
* groupId/artifactId/version/*.jar
修改本地库位置
* 在$M2_HOME/conf/setting.xml文件的<localRepository>元素中指定路径,
* 例如:
<localRepository>D:/my_repository</localRepository>
在Eclipse中创建Maven项目
m2eclipse 是一个在 Eclipse 中集成 Maven 的插件,通过该插件可以很轻松的在 Eclipse 中新建 Maven 项目
在菜单栏中一次选择 File -->New --> Other,然后在搜索框中输入 maven,在下方选择 Maven Project,最后点击最下方的 Next 按钮,如图 1 所示。
新建 Maven 项目时,Eclipse 会提示我们是否跳过 Maven Archetype 选择,直接新建一个简单的 Maven 项目,该项目只包含最基本的 Maven 目录结构。若选择使用 Archetype 新建 Maven 项目,则直接点击 Next 按钮进行下一步。
如果选择使用 Archetype 创建,我们需要选择一个 Archetype(如 maven-archetype-quickstart),最后点击 Next 按钮,如图 3 所示。
接下来,我们需要填写项目的 Group Id、Artifact Id、Version、Package 等信息,最后点击 Finish 按钮,如图 4 所示。
返回 Eclipse 工作区,可以看到 Eclipse 已经为我们创建好了一个 Maven 项目,如图 5 所示
pom.xml
是Maven项目的核心配置文件,位于每个工程的根目录,指示Maven工作的元数据文件。
元素 | 作用 |
---|---|
<project> |
文件的根节点 . |
<modelversion> |
pom.xml使用的对象模型版本 |
<groupId> |
创建项目的组织或团体的唯一 Id |
<artifactId> |
项目的唯一 Id, 可视为项目名 |
<packaging> |
打包类型,一般有JAR,WAR,EAR 等 |
<version> |
产品的版本号 |
<name> |
项目的显示名,常用于 Maven 生成的文档 |
<url> |
组织的站点,常用于 Maven 生成的文档 |
<description> |
项目描述,常用于 Maven 生成的文档 |
<dependencies> |
构件依赖 |
<parent> |
模型继承 |
<dependencyManagement> |
依赖管理 |
<reporting> |
创建报告 |
<build> |
构建 |
<repositories> |
引用第三方仓库 |
<licenses> |
许可 |
源代码
Maven安装
下载安装包
-
地址:http://maven.apache.org/download.html
-
当前版本为3.x
Windows系统下安装:
-
首先需要确认系统中装有JDK(版本1.4+);
-
将压缩包解压到本地磁盘某目录中,该目录则称为安装目录。
- 例如 C:\app\apache-maven-3.0
目录结构:
-
bin Maven的运行脚本
-
boot Maven自己的类装载器
-
conf 该目录下包含了全局行为定制文件setting.xml
-
lib Maven运行时所需的类库
-
...
-
配置环境变量
- M2_HOME=安装目录
-
在path变量中增加%M2_HOME%\bin
-
MAVEN_OPTS=-Xms NNNm –Xmx NNNm
-
(非必要项,可防止内存溢出。其中NNN表示具体的内存数量)
-
-
检查安装正确性
-
在命令行提示符下执行:
-
mvn –v
-
能看到Maven和JDK的版本号为安装正确
-
-
小试Maven命令
*mvn help:system
该命令将会下载help插件并运行它,且打印出Java系统属性和环境变量
Maven常用命令
基础操作
- 检测Maven、JDK版本
- 获取帮助选项
- 显示详细错误信息
- 创建Java项目
示例:
工程管理
- 创建Web项目
- 创建其它项目(例如SSH、JPA、JSF、Seam…)
-
然后根据提示选择项目骨架、groupid、artifactid、版本号…
- Maven3已有上百个项目骨架
-
转换成Eclipse工程
- 转换成idea项目:
生命周期管理
- 编译
- 编译测试代码
- 产生Site:
- 测试
- 清除
- 打包
- 发布
其它操作
- 手动添加构件到仓库
- 复制依赖构件到相应目录
- 示例:
- 显示一个插件的详细信息(configuration, goals等):
核心功能
依赖管理
坐标
一个Java构件的五大坐标元素:
groupId:组ID
artifactId:实际项目的ID
version:版本
package:包类型,如JAR、EAR、POM…
classifier:分类,如二进制包,源、文档
通过这种规则就可以定位到世界上任何一个构件
依赖
依赖配置
依赖传递
Maven 依赖传递是 Maven 的核心机制之一,它能够一定程度上简化 Maven 的依赖配置。本节我们将详细介绍依赖传递及其相关概念。
如下图所示,项目 A 依赖于项目 B,B 又依赖于项目 C,此时 B 是 A 的直接依赖,C 是 A 的间接依赖。
Maven 的依赖传递机制是指:不管 Maven 项目存在多少间接依赖,POM 中都只需要定义其直接依赖,不必定义任何间接依赖,Maven 会动读取当前项目各个直接依赖的 POM,将那些必要的间接依赖以传递性依赖的形式引入到当前项目中。Maven 的依赖传递机制能够帮助用户一定程度上简化 POM 的配置。
基于 A、B、C 三者的依赖关系,根据 Maven 的依赖传递机制,我们只需要在项目 A 的 POM 中定义其直接依赖 B,在项目 B 的 POM 中定义其直接依赖 C,Maven 会解析 A 的直接依赖 B的 POM ,将间接依赖 C 以传递性依赖的形式引入到项目 A 中。
通过这种依赖传递关系,可以使依赖关系树迅速增长到一个很大的量级,很有可能会出现依赖重复,依赖冲突等情况,Maven 针对这些情况提供了如下功能进行处理。
-
依赖范围(Dependency scope)
-
依赖调解(Dependency mediation)
-
可选依赖(Optional dependencies)
-
排除依赖(Excluded dependencies)
-
依赖管理(Dependency management)
依赖范围
首先,我们要知道 Maven 在对项目进行编译、测试和运行时,会分别使用三套不同的 classpath。Maven 项目构建时,在不同阶段引入到 classpath 中的依赖时不同的。例如编译时,Maven 会将与编译相关的依赖引入到编译 classpath 中;测试时,Maven 会将与测试相关的的依赖引入到测试 classpath 中;运行时,Maven 会将与运行相关的依赖引入到运行 classpath 中。
我们可以在 POM 的依赖声明使用 scope 元素来控制依赖与三种 classpath(编译 classpath、测试 classpath、运行 classpath )之间的关系,这就是依赖范围。
Maven 具有以下 6 中常见的依赖范围,如下表所示。
compile:编译范围,默认scope,在classpath中存在
provided:已提供范围,比如容器提供Servlet API
runtime:运行时范围,编译不需要,接口与实现分离
test:测试范围,单元测试环境需要
system:系统范围,自定义构件,指定systemPath
import:导入依赖
赖范围 | 编译classpath | 测试 classpath | 运行classpath | 例子 |
---|---|---|---|---|
compile | √ | √ | √ | log4j |
test | - | √ | - | junit |
provided | √ | √ | - | servlet-api |
runtime | - | √ | √ | JDBC-driver |
system | √ | √ | - | 非Maven 仓库的本地依赖 |
依赖范围对传递依赖的影响
项目 A 依赖于项目 B,B 又依赖于项目 C,此时我们可以将 A 对于 B 的依赖称之为第一直接依赖,B 对于 C 的依赖称之为第二直接依赖。
B 是 A 的直接依赖,C 是 A 的间接依赖,根据 Maven 的依赖传递机制,间接依赖 C 会以传递性依赖的形式引入到 A 中,但这种引入并不是无条件的,它会受到依赖范围的影响。
传递性依赖的依赖范围受第一直接依赖和第二直接依赖的范围影响,如下表所示。
直接依赖/传递依赖 | compile | provided | runtime | test |
---|---|---|---|---|
compile | compile | - | runtime | - |
provided | provided | provided | provided | - |
runtime | runtime | - | runtime | - |
test | test | - | test | - |
注:上表中,左边第一列表示第一直接依赖的依赖范围,上边第一行表示第二直接依赖的依赖范围。交叉部分的单元格的取值为传递性依赖的依赖范围,若交叉单元格取值为“-”,则表示该传递性依赖不能被传递。
通过上表,可以总结出以下规律: 当第二直接依赖的范围是 compile 时,传递性依赖的范围与第一直接依赖的范围一致; 当第二直接依赖的范围是 test 时,传递性依赖不会被传递; 当第二直接依赖的范围是 provided 时,只传递第一直接依赖的范围也为 provided 的依赖,且传递性依赖的范围也为 provided; 当第二直接依赖的范围是 runtime 时,传递性依赖的范围与第一直接依赖的范围一致,但 compile 例外,此时传递性依赖的范围为 runtime。
依赖调节
Maven 的依赖传递机制可以简化依赖的声明,用户只需要关心项目的直接依赖,而不必关心这些直接依赖会引入哪些间接依赖。但当一个间接依赖存在多条引入路径时,为了避免出现依赖重复的问题,Maven 通过依赖调节来确定间接依赖的引入路径。
依赖调节遵循以下两条原则: 引入路径短者优先 先声明者优先
以上两条原则,优先使用第一条原则解决,第一条原则无法解决,再使用第二条原则解决。 引入路径短者优先 引入路径短者优先,顾名思义,当一个间接依赖存在多条引入路径时,引入路径短的会被解析使用。
例如,A 存在这样的依赖关系: A->B->C->D(1.0) A->X->D(2.0)
D 是 A 的间接依赖,但两条引入路径上有两个不同的版本,很显然不能同时引入,否则造成重复依赖的问题。根据 Maven 依赖调节的第一个原则:引入路径短者优先,D(1.0)的路径长度为 3,D(2.0)的路径长度为 2,因此间接依赖 D(2.0)将从 A->X->D(2.0) 路径引入到 A 中。 先声明者优先 先声明者优先,顾名思义,在引入路径长度相同的前提下,POM 文件中依赖声明的顺序决定了间接依赖会不会被解析使用,顺序靠前的优先使用。
例如,A 存在以下依赖关系: A->B->D(1.0) A->X->D(2.0)
D 是 A 的间接依赖,其两条引入路径的长度都是 2,此时 Maven 依赖调节的第一原则已经无法解决,需要使用第二原则:先声明者优先。
A 的 POM 文件中配置如下。
有以上配置可以看出,由于 B 的依赖声明比 X 靠前,所以间接依赖 D(1.0)将从 A->B->D(1.0) 路径引入到 A 中。
多模型开发:继承
通过子项目来继承,可以共享父项目定义的所有的值。比如自定义构建信息,版本仲裁。
特点:
- 单亲父节点
- 从叶节点往上定义的
- 允许覆盖
多模型开发:组合
组合:定义一组构建模块的聚集
特点:
-
组合可以独立于继承
-
上层节点进行组合定义
在POM中使用第三方仓库
例如:
第三方仓库会提供配置信息,详情参考第三方的仓库使用说明
构建配置
一般构建时加上必要的插件就可以,不需要更多的配置,因为它有内部约定。 如果需要改变配置,例如源代码文件夹、编译打包结果文件夹等等,都是可以改变的。
常用插件
Maven编译插件
命令:
该插件是默认插件,如果没有配置,Maven将以1.3级别来编译
JAR包生成插件
命令:
默认插件,如果需要更多的配置(例如jar档案说明信息、选择性打包等等),可以查看官方文档http://maven.apache.org/plugins/maven-jar-plugin/
测试插件
作用:
-
可以跳过测试
-
当测试失败仍然执行
默认插件,也可以命令后面加上参数来替代配置:
-Dmaven.test.skip=true
Tomcat插件
命令:
Tomcat插件常用配置
这些配置适合在Eclipse中通过Maven启动Tomcat来测试自己的Web项目,如果要完全控制Tomcat,并自动将项目发布到Tomcat中,则还需要添加
标签,并在setting.xml中添加Tomcat管理员账号,详情见官方说明:http://mojo.codehaus.org/tomcat-maven-plugin/
自动化部署
CARGO ——自动化部署利器,使Maven如虎添翼
自动化部署:
非官方插件,它可以向Tomcat、Jetty、Resin、JBoss、Glassfish、WebLogic等容器中部署项目。功能非常强大
官方网址:http://cargo.codehaus.org/
部署到Tomcat
向远程Tomcat部署Web项目
命令:
嵌入式Tomcat
嵌入式Tomcat部署Web项目:将Tomcat中间件嵌入到自己的Web工程中。
命令:
Maven插件总结
Maven一切行为都是由插件完成的
artifactId以xxx-maven-plugin形式的是Maven官方插件,一般可以默认使用(不需要配置)
Apache提供的Maven插件列表:
http://maven.apache.org/plugins/index.html
Codehaus提供的Maven插件列表:
http://mojo.codehaus.org/plugins.html
可以开发自己的插件项目,使得Maven功能无限扩展
项目打包生命周期
JAR:将class压缩成JAR包
POM:构件为自己本身
Maven Plugin:Maven插件,如Jetty插件
EJB:企业级JavaBean,支持EJB2、EJB3
WAR:Web工程包
EAR:JavaEE结构体
其它(RAR,SAR,SWF…):理论上只要有插件支持即可