本文最后更新于 659 天前,其中的信息可能已经有所发展或是发生改变。
第一章 Maven简介
1.1何为Maven
maven翻译为“知识的积累”,“内行”,“专家”
作为Apache组织中颇为成功的一个开源项目,Maven主要服务于基于Java平台的项目构建,依赖管理和项目信息管理
1.1.1何为构建
编译,运行单元测试,生成文档,打包和部署
1.1.2Maven是优秀的构建工具
- Maven是跨平台的
- 最大化地消除了构建的重复
- 抽象了构建生命周期
- 提供已实现的插件
- 标准化构建过程
1.1.3Maven不仅仅是构建工具
- 依赖管理工具
- 随着依赖的增多,版本不一致、版本冲突、以来臃肿等问题都会接踵而来。
- Maven提供了一个优秀的解决方案(坐标系统)来定位每一个构件
- 项目信息管理工具
- 项目描述、开发者列表、版本控制系统地址、许可证、缺陷管理系统地址等
- 通过Maven插件,我们能轻松获得项目文档、测试报告、静态分析代码、源码版本、日志报告等有价值的项目信息
- 约定优于配置
- Maven对项目目录结构、测试用例命名方式等内容都有既定的规则
1.2同类工具
- Make
- 强大之处在于它可以利用所有系统的本地命令,达到快速、高效
- 缺点
- 将自己和系统绑定在一起了,无法跨平台
- 语法不友好
- Ant
不是蚂蚁,而是意指“另一个整洁的工具”(Another Neat Tool),最早用来构建Tomcat
- 支持跨平台
- 使用
Xml
定义构建脚本,更加友好 - 缺点
- 针对构建的过程,每个项目都要重新编写
- 没有依赖管理
1.3Maven与极限编程
极限编程(XP)是敏捷开发方法,强调拥抱变化。
- Maven如何帮助XP团队实现一些核心价值
- 简单
- Maven暴露了一组一致、简洁的操作接口,简化构建系统的复杂度
- 交流与反馈
- 与版本控制系统结合,所有人都能执行最新的构建并快速得到反馈
- 自动生成项目报告,帮助成员了解项目的状态,促进团队的交流
- Maven无缝支持或融入到XP的实践中
- 测试驱动开发(TDD)
- TDD强调测试先行,所有产品都应由测试用例覆盖。
- 测试是Maven生命周期中最重要的组成部分之一,提供现成的插件,如
JUnit
,TestNG
- 持续集成(CI)
- CI强调的是项目以最短的周期(如15分钟)集成最新的代码。
- CI的前提是源码管理系统和构建系统
- 目前业界流行的CI服务器
Hudson
,CruiseControl
都能很好的和Maven集成,使用Maven后,持续集成会更加方便 - 富有信息的工作区
- 强调开发者能够快速方便地了解到项目的最新状态。
“只有两类计算机语言,一类语言天天被人骂,还有一类没人用。” ------C 之父
第二章 Maven的安装和配置
- 安装目录介绍
- boot:类加载器框架
- lib:可在这里找到
maven
内置的超级POM
- NOTICE.txt记录了
maven
包含的第三方软件
第三章 Maven使用入门
- POM:
project object model
,项目对象模型 - modelVersion:当前
POM
模型的版本 - SNAPSHOT:快照,说明项目处于开发中,是不稳定版本
- 没有任何
Java
代码,我们就能定义一个Maven
项目的POM
,体现了项目对象模型最大程度的和实际代码独立——解耦 - 代码的包名:
GroupId
ArtifactId
- finalName:自定义打包后的文件名
- jar:jar:
jar
插件的jar
目标 - Archetype:快速生成项目骨架,感觉和
SpringBoot
的Starter
很像,都是一堆jar
包的集合
第四章 背景案例
略
第五章 坐标和依赖
- Maven坐标元素
- groupId:【必须】当前项目隶属的实际项目(公司域名 项目名,例如
org.sonatype.nexus
) - artifactId:【必须】实际项目中的一个
Maven
项目(模块),推荐实际项目作为artifactId
的前缀,例如nexus.indexer
- version:【必须】版本,包括快照(
SNAPSHOT
) - packaging:【可选】打包方式,通常与所产生构件的文件扩展名对应,当不定义时,默认为jar
- classifier:【不能直接定义】帮助定义构建输出的一些附属构件,附属构件与主构件对应,例如通过插件生成如
nexus-indexer-2.0.0-javadoc.jar
。注意,不能直接定义项目的classifiler,因为附属构件不是有项目直接产生的,而是由附加的插件帮助生成
- groupId:【必须】当前项目隶属的实际项目(公司域名 项目名,例如
- 可在方法上使用
@Before
注解,该方法将在@Test
方法之前执行,就行aop
一样,同理还有@After
- 依赖的配置
- groupId、artifactId、version:依赖的基本坐标
- type:依赖的类型,对应项目坐标定义的
packaging
,大部分情况不必声明,默认为jar
- scope:依赖的范围
- option:依赖是否可选
- exclusions:用来排除传递性依赖
- 三套不同的classpath
- 编译classpath:编译项目主代码
- 测试classpath:编译和执行测试代码
- 运行classpath:实际运行项目
- 依赖范围:控制依赖与classpath的关系
- compile:编译依赖范围,如果没指定,默认使用该依赖范围,使用此依赖范围的依赖,对于编译、测试、运行三种
classpath
都有效,例如spring-core
- test:测试依赖范围,使用此依赖范围的依赖,只对于测试classpath有效,在编译主代码或者运行项目时将无法使用此类依赖,比如在主代码里import测试依赖范围的依赖里的class,将会报错。例如Junit,只有在编译测试代码和运行测试代码时才需要
- provided:已提供依赖范围,使用此依赖范围的依赖,对于编译和测试classpath有效,运行时无效。例如springboot项目打war包时,需要将web-starter里的tomcat依赖排除掉,然后单独添加一个tomcat的依赖,并设置依赖范围为provided,这样打包后,lib目录下将没有tomcat的jar包,这样便可放到tomcat里运行了
- runtime:运行时依赖范围,使用此依赖范围的依赖,对于测试和运行的classpath有效,编译时无效。例如JDBC驱动实现,项目主代码编译时只需要JDK提供的JDBC接口,只是在执行测试或者运行项目的时候才需要实现上诉接口的具体JDBC驱动
- system:系统依赖范围,与classpath的关系与provided一样,使用此依赖范围必须通过systemPath元素显示地指定依赖文件的路径,systemPath可使用环境变量,例如${java.home}/lib/rt.jar。实际项目示例
- compile:编译依赖范围,如果没指定,默认使用该依赖范围,使用此依赖范围的依赖,对于编译、测试、运行三种
- import:导入依赖范围。该依赖范围不会对三种classpath产生实际的影响
- 传递性依赖和依赖范围
第一直接/第二直接 | compile | test | provided | runtime |
---|---|---|---|---|
compile | compile | runtime | ||
test | test | test | ||
provided | provided | provided | provided | |
runtime | runtime | runtime |
- 依赖调解
- 第一原则:路径最近者优先
- 第二原则:第一声明者优先
- 可选依赖
<optional>true</optional>
- 不会被传递
- 排除依赖
<exclusion></exclusion>
- 只需要
groupId
和atfactId
,不需要version
- 归类依赖
- 使用
<properties></properties>
来控制某类依赖的版本,例如spring
- 使用
- 优化依赖
- Maven会自动解析所有项目的直接依赖和和传递性依赖,并且根据规则判断每个依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构件只有一个版本的依赖存在。
- 最后得到的依赖称为已解析依赖。可通过命令查看
mvn dependency:list
,还可以通过树的形式查看mvn dependency:tree
- 最方便的还是Idea的maven help插件
mvn dependency:analyze
分析依赖,可以得到未声明但被使用的依赖,和声明但未被使用的依赖
- 关于解决依赖冲突、优化依赖,可以看看这篇文章,比较实用
第六章 仓库
Maven
项目不再各自存储其依赖文件,只需声明坐标,在需要的时候(例如,编译项目的时候需要将其加入到classpath中),Maven
会自动根据坐标,找到仓库中的构件,并使用他们- 依赖的查找
- 本地仓库—>私服—>其他公共库(阿里、网易)—>中央仓库
- 远程仓库的配置
- setting.xml
- pom.xml里的
<repository></repository>
<layout></layout>
指仓库布局<snapshots></snapshots>
配置是否下载快照版- 注意:以ID区分,相同会覆盖
- 私服的优点
- 节省外网宽带
- 加速Maven构建(Maven构建时会检查快照版本是否为最新)
- 部署第三方构建(二方包也可以)
- 降低中央仓库的负荷
- 提高稳定性,增强控制
mvn clean deploy
部署到远程仓库
第七章 生命周期和插件
- Maven的生命周期是抽象的,其实际行为都由插件来完成(设计模式:模板方法)
- 生命周期抽象了构建的各个步骤,定义了他们的次序,但没有提供具体的实现
- 三套相互独立的生命周期:clean、default、site
生命周期 | 目的 | 包含的阶段 |
---|---|---|
clean | 清理项目 | 三个:pre-clean、clean、post-clean |
default | 构建项目 | 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 |
site | 建立项目站点 | 4个:pre-site、site、post-site、site-deploy |
- 插件目标
- 一个插件包含多个功能,每个功能对应一个插件目标
- maven-dependency-plugin有十多个目标
- 分析依赖冲突:mvn dependency:tree -Dverbose
- 查看声明但未被使用的依赖:mvn dependency:analyze-only
- 查看重复声明的依赖:mvn dependency:analyze-duplicate
- 绑定生命周期与插件
- 为了让用户不用任何配置就能构建Maven项目,maven内置绑定了一些核心的生命周期与插件目标
- 支持自定义绑定
- Maven 生命周期的阶段与插件的目标之间的绑定关系
- clean 生命周期
clean 生命周期的阶段 插件的目标 pre-clean clean maven-clean-plugin:clean post-clean
- default 生命周期的内置插件绑定关系及具体任务(打包类型:jar)
生命周期阶段 插件目标 执行任务 process-resources maven-resources-plugin:resources 复制主资源文件至主输出目录 compile maven-compiler-plugin:compile 编译主代码至主输出目录 process-test-resources maven-resources-plugin:testResources 复制测试资源文件至测试输出目录 test-compile maven-compiler-plugin:testCompile 编译测试代码至测试输出目录 test maven-surefire-plugin:test 执行测试用例 package maven-jar-plugin:jar 创建项目 jar 包 install maven-install-plugin:install 将项目输出构件安装到本地仓库 deploy maven-deploy-plugin:deploy 将项目输出构件部署到远程仓库 注意:上表只列出了拥有插件绑定关系的阶段,default 生命周期还有很多其他阶段,默认它们没有绑定任何插件,因此也没有任何实际行为。
- site 生命周期
site 生命周期的阶段 插件的目标 pre-site site maven-site-plugin:site post-site site-deploy maven-site-plugin:deploy
第八章 聚合与继承
- 约定 一般来说,一个项目的子模块都应该使用相同的groupId,如果他们一起开发和发布,还应该使用同样的version
- 聚合项目的packaging必须为pom,否则无法构建
- 通过module元素来实现聚合
- 聚合项目并非一定是父子关系,例如平行关系
- 使用平行目录结构时,需要注意module元素为相对路径,例如
<module>../xxxx</module>
- 对聚合的pom执行maven命令时,maven会先解析pom,分析要构建的模块,并计算出一个反应堆构建顺序,然后根据这个顺序构建模块
- 反应堆
- 对于单模块项目,反应堆就是其本身
- 对于多模块项目,反应堆指所有模块组成的一个构建结构,包含各模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序
- 先分析pom,如果该模块没有依赖与其他模块,则先构建,如果依赖了,则先构建依赖的模块
- 继承
- 父容器的packaging必须为pom
- 子项目包含parent元素
- 子项目构建时会根据relative元素检查父pom,如果找不到,再从本地仓库查找,relative默认值为
../pom.xml
- 父项目设置dependencymanagement,约束子项目dependencies下的依赖,可以打破解决依赖冲突时,maven的两大仲裁原则(路径最短优先,先声明优先)
- 通过scope为import,type为pom,引入其他pom的dependencymanagement
- 插件管理:pluginmanagement
- 约定大于配置
- Maven核心设计理论
- 大量减少配置,开箱即用
- 例如目录结构(当然也可以自定义,不过得付出代价,个性往往意味着失去通用性,增加复杂性)
Post Views: 350