SQ3R:
Survey
1、这本书是国内首个Maven著作,而并非 xx in action的翻译;
2、基于Maven 3;
question
1、Maven这一优秀的技术为什么没有得到广泛的推广?
Maven陡峭的学习曲线、文档匮乏!
2、Maven的前世今生??
3、什么情境下诞生了Maven?
4、Maven主要是用来做什么的?
跨平台的项目管理工具、自动化构建、依赖管理,使项目经理更高效、规范地管理项目!
5、Maven与Ant的区别?
- Maven
- 自动化构建、管理项目
- 跨平台
- 为全世界java开发者提供中央仓库,自动下载构件
- 对第三方类库进行依赖管理
- 管理分散在项目各个角落的项目信息:项目描述、开发者列表、版本控制系统、许可证、缺陷管理系统地址等
- 对项目的目录结构、测试用例命名方式等都有既定的规则,遵循既定规则,免去学习成本,即约定优于配置(Convention Over Configuration)
- Ant
- 只能是自动化构建,不能进行项目管理
- 跨平台
read
第一章 Maven简介
1、何为Maven?
- 跨平台的项目管理工具
- 服务于基于java平台的项目构建、依赖管理、项目信息管理
- 能够管理的项目规模:从小型的开源类项目到大型的企业级应用
- 能够适用于的开发模式:从最早的瀑布模型到最新的敏捷开发
2、Maven与构建管理工具的比较
比喻:购买品牌电脑 vs 自己组装电脑
当你需要一个电脑时,Maven更像是直接购买一个品牌电脑,而其他工具更像是自己动手组装一台电脑;前者让你省时省力,好能享受售后服务,后者享受组转过程但是费时费力,还不太稳定。
- IDE工具:IDE不是万能的
- 优点:
- IDE能够提供强大的文本编辑、调试甚至重构功能
- 缺点:
- 依赖大量的手工操作:编译、测试、代码生成等工作相互独立,难以一键完成,低效、易出错
- 难以在项目中统一所有的IDE配置,每个人都有自己的喜好,造成一个在机器A上运行的任务在机器B上运行失败
- 总结:不能过于依赖IDE,集成Maven,在IDE中使用Maven
- 优点:
- make:最早的构建工具
- 优点:
- make由一个名为Makefile的脚本文件进行驱动,使用make自己定义的语法,基本组成部分是一系列的Rules、Targets、Prerequisite、Command,将整个构建过程串联起来
- 极大限度地利用系统的本地命令,以系统耦合紧密
- 缺点:
- 与操作系统耦合紧密,不能实现跨平台,对java相当不友好
- makefile的语法容易出错
- 优点:
- Ant:Another Neat Tool(意为“另一个整洁的工具”,而非“蚂蚁”)
- 优点:
- 最早用来构建Tomcat,因为作者受不了make的语法格式而创造Ant
- Ant可以看成是java版本的make,解决了make的跨平台问题;Ant使用XML文件,解决了makefile的语法格式问题
- 缺点:
- Ant是过程式的,开发者显式地制定每一个目标,以及完成该目标需要执行的任务(Maven是声明式的,构建过程基本都有现成的插件实现,开发者只需声明项目的基本元素即可)
- 针对每一个项目,都要重新编写一遍这一过程,隐含很大的重复(Maven开发者声明了项目基本元素之后,由Maven执行内置的构建过程,消除大部分重复)
- Ant原来没有依赖管理,现在可以依赖Ivy进行依赖管理(Maven内置了依赖管理功能)
- 优点:
3、Maven目前存在的问题
- Maven比较复杂
- Maven是用来管理项目的,而清理、编译、测试、打包、发布等这一过程本身就很复杂,所以我们要做的是帮助Maven变得简单;
- Maven的中央仓库比较混乱
- Maven的中央仓库确实不完美,甚至会发现某个jar包出现在两个不同的路径下,,这不是Maven的错,而是开源项目本身改变了自己的坐标,所以我们可以建立自己组织内部的仓库服务器,这会为你带来意想不到的好处。
- Maven缺乏文档
- 这个确实是事实,maven的站点文档比较凌乱。
第二章 Maven的安装与配置
1、在windows下安装
- 安装JDK
- 下载Maven压缩包、解压、设置环境变量%M2HOME%
- 加入path路径下,ok!
2、基于UNIX系统上安装(略)
3、Maven安装目录分析
- bin
- 包含mvn运行的脚本,这些脚本用来配置java命令,准备好classpath和相关的java属性,然后执行java命令。
- boot
- 只包含一个jar文件,是maven自己的类加载器框架,相比java的类加载器框架,它提供了更丰富的语法以方便配置。
- conf
- 包含有重要文件settings.xml,修改该文件可以在全局上定制maven行为;
- 一般会把该文件复制到~/.m2/目录下,在用户范围内定制Maven行为(~表示用户目录,如C:\user\xxx\,C:\Document and Settings\XXX\)
- lib
- 放置maven自身需要的一些jar包
- LINCENSE.TXT
- NOTICE.TXT
- README.TXT
4、设置HTTP代理
- 复制settings.xml文件至~/.m2/目录,修改其中的<proxies>标签中内容
5、安装m2eclipse插件
- eclipse是一个强大的IDE,集成了很多工具,JUnit、CVS、SVN等,但是没有集成Maven
- Maven之父Jason Val Zyl为我们制造了m2eclipse插件
- 安装可能出现问题:更换eclipse默认的JRE
6、安装netbeans Maven插件
- 6.7以上的版本已经预装了Maven插件
7、Maven安装最佳实践
- 设置MAVEN_OPTS环境变量
- 设置MAVEN_OPTS环境变量的值为-Xms128m -Xmx512m,
- 因为mvn实际上是运行java命令,而java默认的内存往往不能够满足Maven的运行需要,所以需要该配置;
- 配置用户范围的settings.xml
- 复制settings.xml文件到~/.m2/目录,修改后结果只影响到机器上这一用户,不能影响系统下其他用户;
- 直接修改conf文件夹下settings.xml会影响到整个机器上的Maven行为
- 不要使用IDE内嵌的Maven
- IDE内的maven一般会比较新(如果是新版本的IDE的话),这样的Maven不是很稳定
- 除了在IDE内部,其他时候我们会使用命令行的Maven,如果版本不一样,会造成不一样的结果,算是IDE不是万能的一条吧
第三章 Maven使用入门
1、编写POM
- 就像ant中的build.xml一样,Maven中需要编写pom.xml(Project Object Model 项目对象模型)
- pom.xml文件的组成(只有一个根元素,五个子元素)
- 根元素<project>,这点跟build.xml一样
- <modelVersion>:对于maven2和maven3,只能是4.0.0
- <groupId>:定义项目属于哪个组,如com.google.myapp,
- <artifactId>:定义当前项目在<groupId>中的唯一ID,如hello-world
- <version>:定义当前<groupId>中当前<artifactId>项目的版本号
- <name>:没有实际意义,但是推荐一个有意义的项目名字
- pom.xml中不涉及任何java代码,与项目代码相对立(解耦),很大程度上避免了java代码和POM代码的相互影响
- 向项目需要升级时,只需修改POM,不需修改java代码;而当POM稳定之后,日常的java代码开发工作不涉及POM代码
2、编写主代码
- 项目主代码会被打包到项目最终的构件中(如jar),项目测试代码则不会
- 约定存在主代码目录:src.main.java
- 约定java类的包名:与pom.xml中的groupId、artifactId一致
3、编写测试代码
- 约定项目测试代码目录:src.test.java
- 要使用JUnit进行测试,需要在pom.xml中添加JUnit依赖
4、打包和运行
- 命令:mvn clean package
- 命令:mvn clean install
- 命令:mvn clean compile
5、使用Archetype生成项目骨架
- 针对maven3:mvn archetype:generate
- 根据提示输入groupId、artifactId等信息
- 自动生成各种约定好的文件夹结构
6、m2eclipse的简单使用(略)
7、netbeans maven插件简单使用(略)
第四章 背景案例(略)
第五章 坐标和依赖
1、何为Maven坐标?
- 用坐标去确定唯一的构件,即jar、war等文件
- Maven定义:世界上任何一个构件都可以使用Maven坐标唯一标示
- Maven坐标的元素:groupId、artifactId、version、packaging、classifier。
2、Maven坐标详解
- groupId(必须)
- 定义当前Maven项目隶属的组织机构中实际存在的项目
- 不要对应在组织机构层(组织机构层范围太大)
- Maven项目和实际存在项目不一定是一对一的关系(实际存在项目包括多个Maven项目)
- artifactId(必须)
- 对应组织机构中实际存在项目中的某个Maven模块
- version(必须)
- 定义当前Maven模块的版本号
- packaging(可选)
- 定义Maven项目的打包模式,jar、war等
- classifier(不能直接定义)
- 帮助定义构建输出的一些附属构件,如xxx-javadoc.jar、xxx-sources.jar等
3、依赖配置的基本元素
- groupId、artifactId、version:依赖的基本坐标,最重要
- type:依赖的类型,对应于项目坐标定义的packaging,大部分情况下不用声明,默认为jar
- scope:依赖的作用范围
- optional:标记依赖是否可选
- exclusions:用来排除传递性依赖、
4、依赖范围
- Maven项目有三种classpath(编译classpath、测试classpath、运行classpath);
- 依赖范围就是控制依赖(如junit等)与这三张classpath的关系
- 依赖范围的分类
- compile——编译依赖范围,是Maven的默认依赖范围,对编译、测试、运行classpath都有效;
- test——测试依赖范围,只对测试classpath有效;
- provided——已提供依赖范围,只对编译、测试有效。对运行无效;
- runtime——运行时依赖范围,对测试、运行有效,对编译无效;
- system——系统依赖范围,与provided一致,但是与系统绑定,易造成不可移植,慎用;
- import——导入依赖范围,对三类classpath没有实际影响
5、传递性依赖
- 什么叫传递性依赖?
- A.jar在compile范围内依赖B.jar,B.jar在compile范围内依赖C.jar,所以A.jar在compile范围内依赖C.jar
- 省去了手动添加jar包的问题
- 传递性依赖和依赖范围
- A——>B:第一直接依赖范围
- B——>C:第二直接依赖范围
- A——>C:传递性依赖范围
6、依赖调解
- 传递性依赖存在的问题
- 在项目A中:A——>B——>C——>X(1.0);A——>D——>X(2.0);X是A的传递性依赖,但是两个路径上的X版本不同,此时应该选择哪个X?
- 在项目A中:A——>B——>X(1.0);A——>D——>X(1.0);X是A的传递性依赖,但是路径相同,此时应该选择哪个X?
- 解决两个问题的原则
- 原则一:路径不同时,路径最短者优先
- 原则二:路径相同时,第一声明者优先
7、可选依赖
- 可选依赖不会传递
- 尽量不使用可选依赖
8、最佳实践
- 排除依赖——排除传递性依赖
- 传递性依赖会出现以下隐患:A—>B—>C,但是B中对C的依赖可能是一个不稳定的版本,会造成A失败;
- 使用<exclusion>排除依赖,然后再显式地声明依赖,即把依赖关系A—>B—>C,变成A—>B,A—>C,并在显式依赖中指定稳定版本的版本号,去除依赖不稳定版本的隐患
- 归类依赖——与代码重构的思想相同,用变量代替常量
- 比如:在项目中存在对Spring Framework的依赖,有org.springfarmework:spring-core:2.5.6、org.springfarmework:spring-context:2.5.6org.springfarmework:spring-beans:2.5.6org.springfarmework:spring-context-support:2.5.6,他们来自同一项目不同模块,当Spring Framework升级时,他们的版本号会一同升级,所以借鉴代码重构的思想,应该用变量代替常量;
- 使用<properties>标签,定义变量,在<version>标签中使用${元素名}代替常量;如
- 优化依赖——同样是重构的思想,经常对依赖进行重构、优化
- 程序员应该对Maven项目的依赖了然于胸,经常进行优化,去除多余的依赖,显示声明必要的依赖;
- 对于存在冲突的依赖,进过两个原则之后,只会存在一个版本的依赖,这些依赖成为已解析依赖(Resolved Dependency)
- 使用命令mvn dependency:list,mvn dependency:tree查看项目依赖
- 使用mvn dependency:analyze进行分析,查看Used undeclared dependencies和Unused declared dependencies
- Used undeclared dependencies(使用了未显式声明的依赖):存在风险,尽快排除
- Unused declared dependencies(没有使用显式声明的依赖):这种依赖不能盲目删除,因为该命令只是分析编译,并不能分析测试和运行
第六章 仓库
1、何为仓库?
- 存在jar、war等各种构件的地方
- 分为本地仓库(只有一个)和远程仓库(可以有很多)两种,可类比为自己家的书房(只一个)和书店(很多),各种构件就是各种书籍
- 本地仓库的存放位置:.m2/repository/,可以在.m2/settings.xml中修改仓库存放路径
- 仓库的布局
- 路径与坐标的对应关系为groupId/artifactId/version/artifactId-version.packaging,如groupId=org.testng、artifactId=testng、version=5.8、classifier=jdk1.5、packaging=jar,那么仓库中路径为:org/testng/testng/5.8/testng-5.8-jdk1.5.jar
2、本地仓库、远程仓库、中央仓库、私服
- 本地仓库在刚安装Maven时是空的,必须执行Maven命令后才会生成;
- 由于最开始本地仓库是空的,Maven必须知道一个远程仓库才能下载构件到本地仓库,这个默认的远程仓库就是中央仓库(Maven安装时自动配置了中央仓库);
- 私服是特殊的远程仓库,架设在局域网内部,供局域网内部Maven项目使用
- 当本地Maven项目需要下载构件时,先去私服请求,如果私服没有,则去远程仓库请求,从远程仓库下载构件后,把构件缓存在私服上,为下次请求服务。
- 本地Maven项目也可以上传构件到私服
- 建立私服的好处——即使在一台直接接入internet的个人机器上也应该设立私服
- 节省外网带宽——直接从私服下载,不用经过外网
- 加速Maven构建——下载速度更快
- 部署第三方构件——上传构件,供他人使用
- 提高稳定性,增强控制——Maven的构建高度依赖于远程仓库,当internet连接不稳定时,Maven甚至无法构建,设立私服后,不存在该问题
- 降低中央仓库的负荷——维护一个中央仓库费时、费财、费力
3、远程仓库的配置
- 一个Maven项目会用到很多构件,来自不同的远程仓库,可以在pom.xml中使用<repository>进行配置
- 一般不需要认证即可下载,需要认证时,使用<server>标签进行配置用户名及密码
- 部署构件到远程仓库时,使用<distributionManagement>标签
4、快照版本
- 小李在开发模块A,小张在开发模块B,B依赖A,但是A还没有稳定版本,但是B希望总是使用A的最新版本进行构建
- 设置A的版本为2.1-SNAPSHOT发布到私服上,Maven在发布过程中会自动打上时间戳,而B在构建时,会根据时间戳自动寻找A的最新版本
- 当项目发布时,只用把快照版本改为稳定版本即可
5、从仓库解析依赖的机制(即如何根据依赖的版本从仓库获取构件)
6、镜像
- 如果仓库A可以提供仓库B存储的所有内容,那么仓库A就是仓库B的一个镜像(A>=B)
- 可以在settings.xml中修改<mirror>标签内容,选择速度最快的镜像
7、仓库搜索服务——如何根据项目依赖的构件名称得到构件的具体坐标
- Sonatype Nexus——目前最流行的开源Maven仓库管理软件
- Jarvana
- MVNbrowser
- MVNrepository
第七章 生命周期及插件
1、生命周期
- Maven生命周期是为了对所有的构建过程进行抽象和统一;
- Maven生命周期包括了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤;
- 但是Maven生命周期不是一个整体,Maven生命周期拥有相互独立的三套生命周期,clean、default、site;
- clean生命周期——清理项目
- pre-clean:执行清理前需要完成的工作;
- clean:清理上一次构建生成的文件;
- post-clean:执行一些清理后需要完成的工作;
- default生命周期——定义了真正构建时所需要执行的步骤
- validate
- initialize
- generate-sources
- process-sources:处理项目主资源文件,进行变量替换、复制文件到classpath目录等工作
- generate-resources
- process-resources
- compile:编译项目主源码,输出到主classpath目录
- process-classes
- generate-test-sources
- process-test-sources:处理项目测试资源文件,变量替换、复制文件到classpath目录等工作
- generate-test-resources
- process-test-resources
- test-compile:编译项目的测试代码,输出到主classpath目录
- process-test-classes
- test:使用单元测试框架进行测试
- prepare-package
- package:接受编译好的代码,打包成可发布格式
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install:将包上传到本地Maven仓库,供他人使用
- deploy:将最终的包复制到远程仓库,供他人使用
- site生命周期——建立和发布项目站点
- pre-site
- site:生成项目站点文档
- post-site
- site-deploy:将生成的项目站点发布到服务器上
- 命令行与生命周期
- mvn clean:clean生命周期中pre-clean、clean;
- mvn test:default生命周期中从validate直到test阶段;
- mvn clean install:clean生命周期中pre-clean、clean;default生命周期中从validate直到install阶段;
- mvn clean deploy site-deploy:clean生命周期中pre-clean、clean;default生命周期中所有阶段;site生命周期中所有阶段;
2、插件目标与绑定
- 一个插件中会包含n个功能,这n个功能就是n个插件目标;
- Maven生命周期中的任务都是通过插件完成的,生命周期与插件相互绑定;
- 内部绑定的插件目标与生命周期阶段——生命周期中没有绑定的其他阶段,因为没有插件目标,所以没有实际的行为
- 用户自定义的绑定——通过自定义绑定,实现更强大的任务
3、插件配置
- 在完成插件与生命周期的绑定之后,需要进行插件参数的配置,有命令行参数配置、POM中插件全局配置、POM中插件任务配置
第八章 聚合与继承
1、聚合——为了同时构建多个Maven模块
- 聚合时首先要建立聚合文件夹和聚合pom.xml文件;
- 聚合文件夹中只包含聚合pom.xml,可以与被聚合模块是父子关系或者是平行关系;
- 聚合pom.xml中的packaging类型只能是pom;
- 使用<moduel>标签声明被聚合的Maven子模块;
2、继承——消除聚合时的重复,子模块继承父模块的定义
- 格式与聚合类似,首先要建立父类文件夹和聚合父类pom.xml文件;
- 父类文件夹中只包含父类pom.xml;
- 父类pom.xml中的packaging类型只能是pom;
- 聚合模块和父类模块可以合二为一!
3、反应堆(Reactor)——指Maven项目中所有Maven模块组成的构建结构
- 反应堆的构建顺序:读取POM文件,优先构建依赖模块,其次按声明顺序构建各个模块;
- 裁剪反应堆:即单独构建反应堆中的某一个模块,使用命令mvn -h查看命令
第九章 使用Nexus创建私服(略)
第十章 使用Maven进行测试(略)
第十一章 使用Hudson进行持续集成(略)
第十二章 使用Maven构建web应用:Cargo实现自动化web部署(略)
第十三章 版本管理
- 区分版本管理(快照版、发布版等)和版本控制系统(SVN、CVS等);
- GPG实现构件签名
第十四章 灵活的构建——针对不同的环境灵活配置、构建
第十五章 生成项目站点——定义关于该项目的所有信息(各种报告、界面等)
第十六章 m2eclipse——使用m2eclipse进行Maven项目开发
第十七章 编写Maven插件
第十八章 Archetype——快速生成项目骨架,深入解析Archetype
recite
reciew