Maven是什么
Maven是优秀的构建工具:
构建是指项目的清理、编译、测试到生成构建报告、再到打包和部署的过程,使用java原生命令或者在IDE中操作,只能执行构建中的某一步操作,而Maven能帮助我们自动化的构建,我们甚至只需要一个命令就能执行上诉构建的所有操作。
maven是跨平台的,意味着你不再受平台约束。
Maven是一个依赖管理工具和项目信息管理工具:
Maven能帮我们管理项目中要使用的构件,我们不再为找不到jar包或者版本冲突而痛苦。它提供了中央仓库,能帮我们自动下载构件。它通过一个坐标系统准确地定位每一个构件(artifact),也就是通过一组坐标Maven能够找到任何一个Java类库(如jar文件),于是我们可以借助它来有序地管理依赖。
Maven还能帮助我们管理原本分散在项目中各个角落的项目信息,包括项目描述、开发者列表、版本控制系统地址、许可证、缺陷管理系统地址等。典型的项目会有开发环境、预发环境和线上环境,Maven还能对不同环境所依赖的配置进行管理,使我们的项目能在不同的环境下灵活的切换。
Maven追求的两个目标:约定优于配置、高可扩展性:
约定优于配置:不同于Make、Ant等传统构建工具,Maven制定了一系列的规则,来规范和约束项目的组织结构和构建过程,通过这种方式降低了Maven的学习成本和使用成本。
高可扩展性:Maven在大多数情况下的使用提供了默认的实现,当我们需要更加精细控制时,我们可以配置已有插件,或者添加新的插件,类似我们还可以定义自己的仓库、archetype等等。
Maven的安装与配置
在此文中不再赘述,请看专栏内的这篇文章:http://blog.csdn.net/troy__/article/details/38826553 。
Maven使用入门
我们通过手动写一个HelloWorld的Maven程序来看看Maven的基本组成。
在此文中不再赘述,详细内容请看专栏内这篇文章:http://blog.csdn.net/troy__/article/details/38851903 。
Maven坐标与依赖
坐标是Maven实现依赖管理功能的基础,Maven通过为任何一个构件定义一个唯一的标示来确定该构件的归属及版本。
依赖管理要解决三个主要问题:1. 构件从何来? 2. 怎么解决构件冲突? 3. 如何管理项目持续的版本?
对于第一个问题,Maven定义了仓库,将不同来源的构件都放在仓库中集中储存。关于仓库,我们下一节将详细讲述。
对于第二个问题,通过分析可以知道,构件冲突主要是由于传递性依赖引起的,即类似于同时出现A->B->C,又出现A->C的情况。Maven通过定义一系列的规则解决依赖冲突的问题,简单来说第一原则是:路径最短者优先,第二原则:第一声明者优先,即根据POM中依赖声明的顺序决定谁会被解析使用,顺序最靠前的那个依赖优先。
对于第三个问题,通过版本的定义,我们可以对软件持续的开发和发布定义状态。maven定义了快照版本SNAPSHOT,快照版本主要有两个作用。(1). 用于区分稳定与不稳定的构件:那么发布版本就是稳定的,快照版本就是不稳定的。(2). 用于避免由于版本升级导致不停地升级版本号,造成版本号的泛滥的问题。(这就是"快照"这个词的含义)。
Maven的依赖管理还提供了对依赖构件更加精细的控制的能力
1. 依赖范围
Maven项目在执行编译、测试、运行时执行的是三套不同的classpath,我们在引入依赖的时候,可以限制其依赖范围,这样可以避免其对其他环境造成污染。
2. 可选依赖
可以定制自身项目的某些依赖不会被得以传递。
3. 排除依赖
可以排除掉指定的传递性依赖,通常是由于这个传递性依赖的版本问题需要替换掉,排除后直接在本项目中声明某个版本的该构件即可。
除此之外,Maven还提供了几个工具用于分析当前项目用到的依赖,便于我们对其使用进行优化。关于Maven传递和依赖的详细内容,可以查看专栏内的另一篇文章:http://blog.csdn.net/troy__/article/details/38903737。
Maven仓库
Maven仓库解决了构件从哪来的问题。下面是Maven仓库的组织结构图:
可以把Maven的仓库想象成一棵倒立的树,而我们的终端就是叶子节点,中央仓库则为根,私服则是树中间的节点,我们的从叶子节点一步步往上去寻找项目所需的构件,先是本地仓库,然后私服,再是中央仓库。设立的私服的目的主要是:提高相应速度、节省带宽,内部构件共享。
在实际工作中,我们都会搭建私服,查找和部署构件,私服配置代码一般与具体项目无关,所以我们都放在settings.xml中,下面展示一段典型的仓库配置代码:
<servers> <server> <id>release</id> <username>releaseAdmin</username> <password>123456</password> </server> <server> <id>snapshots</id> <username>snapshotsAdmin</username> <password>123456</password> </server> </servers> <mirrors> <mirror> <id>jymirror</id> <mirrorOf>central</mirrorOf> <name>jiangye mirror</name> <url>http://mvnrepo.jiang.ye.com/mvn/repository</url> </mirror> <mirror> <id>jymirror-snapshots</id> <mirrorOf>snapshots</mirrorOf> <name>jiangye mirror snapshots</name> <url>http://mvnrepo.jiang.ye.com/mvn/repository</url> </mirror> </mirrors> <profiles> <profile> <id>nexus</id> <repositories> <repository> <id>central</id> <url>http://mvnrepo.jiang.ye.com/mvn/repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>snapshots</id> <url>http://mvnrepo.jiang.ye.com/mvn/repository</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> <url>http://mvnrepo.jiang.ye.com/mvn/repository</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>snapshots</id> <url>http://mvnrepo.jiangye.ye.com/mvn/repository</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <activeProfile>nexus</activeProfile> </activeProfiles>
上面的代码定义了构件、插件的仓库,利用私服替代了远程仓库。
关于仓库的详细内容,请看专栏内的另外一篇文章:http://blog.csdn.net/troy__/article/details/38962277。
生命周期与插件
Maven将整个构建的过程抽象出来定义了一套生命周期。主要包括:清理、主资源文件的处理、主代码编译、测试资源的处理、测试代码的编译、测试、打包、安装、部署到远程仓库、发布站点等待。
我们可以从命令行调用Maven任务执行相应的生命周期操作,执行某一生命周期时,该周期前面所有周期都将顺序执行。Maven为每一个生命周期都绑定在了一个默认的插件目标上,我们可以通过插件的配置来跳过某些周期或者定制化某些周期的行为,这便是插件的作用。例如我们常用的跳过测试的命令行操作:
$mvn install -Dmaven.test.skip=true
除了内置绑定,我们还可以自己选择将某个插件目标绑定到某个生命周期上,执行一些额外的任务,比如利用maven-source-plugin生成项目的jar文件。
除此之外,Maven也支持从命令行直接调用一些插件,因为这些插件自身不适合绑定在某个生命周期上,比如maven-help-plugin:descirbe,这是maven帮助提示插件。
关于生命周期与插件的详细内容,请看专栏内的另外一篇文章: http://blog.csdn.net/troy__/article/details/39031687。
聚合和继承
一个项目在实际工作中,通常会根据各种方式将其划分成多个模块,以获得更清晰的设计或者灵活性。我们通常会定义一个独立的POM,让其他子模块来依赖该pom,这样我们的构建和依赖管理等行为都可以通过该pom来实现,即化简了使用,也达到了控制的目的。这种方式被称为聚合(将多个模块聚合到一个pom上)和继承(子模块继承父模块的信息,包括项目自身信息及依赖、插件等)。
关于聚合和继承的详细内容,请查看http://blog.csdn.net/troy__/article/details/39085611 。
使用Nexus创建私服
创建私服的过程在平常使用较少,在此不再赘述,详细内容请查看http://blog.csdn.net/troy__/article/details/39207531。
使用Maven进行测试
利用Maven来进行项目范围的单元测试是一种很好的习惯,但是在我周围的工作中却使用较少,原因有如下:
1. 所负责的项目切换较快,通常都是在前人的项目上进行开发和维护,因此前面会留下大量的过期的单元测试,要对其进行整理,是件成本很高的事。
2. 相对十分依赖功能的回归测试,而非单元测试。
只有在开发新功能时,才会对新添加的功能写单元测试的代码。
关于Maven对测试支持的相关内容,请查看http://blog.csdn.net/troy__/article/details/39233529。
使用Maven创建Web应用
在使用Maven创建Web应用时,我们通常会创建一个独立的模块webapp出来,用以存放与Web密切相关的文件,如web.xml、各种配置文件、html、jsp、css、JavaScript等等。
通过使用一些容器的maven插件,我们把项目热部署到容器上,避免我们来回修改文件导致的打包部署等操作。不过在工作中用的还是很少的,因为一般IDE都有集成容器的插件,我们可以在IDE"点两下"就能实现热部署。
有需要的朋友,可以查看这篇文章http://blog.csdn.net/troy__/article/details/39298847,了解更详细的内容。
灵活的构建
在实际开发过程中,通常会有所谓的开发环境、测试环境和产品环境,这些环境中的各项配置不尽相同,比如数据库配置、缓存配置、RFC配置,那么项目构建的时候就需要能够识别所在的环境并使用正确的配置。为此,Maven提供了三大特性:属性、Profile和资源过滤。
我们将可变的部分利用Maven属性进行替代,而将Maven属性定义在Profile中,再在构建时打开指定Profile即可实现各种环境的灵活切换。
(当下许多公司的"开发平台"、"协作平台"都是基于Maven来实现的。)
了解这些知识对于理解项目的开发和构建有很好的帮助。关于这一节的详细内容请看这篇文章:http://blog.csdn.net/troy__/article/details/39347247。
常用的几个知识点
1. 在集成了maven的IDE中直接pom添加依赖,会触发jar包的更新及引入。
2. 我们经常使用命令:mvn clean eclipse:eclipse -U -DdownloadSources=true,将maven项目转为eclipse项目,并下载源码。
3. src\main\resources及src\test\resources在默认情况下maven不会帮我们创建,需要我们手动创建,如果需要使用maven属性,记得要在pom配置资源过滤。