Maven原理
一、Maven项目结构
1. Maven构建工具
项目依赖管理,管理原本分散在项目各个角落的的项目信息(项目描述、开发者列表、版本控制系统地址、缺陷管理系统地址等)
免费中央仓库,衍生工具Nexus用于快速搜索,依赖包自动下载
约定优于配置(对项目目录结构、测试用例命名方式等内容有既定规则)
2. Maven项目结构
src/main/java:项目java类文件位置 src/main/resources:项目配置资源文件位置 src/test/java:项目单元测试java类文件位置 src/test/resources:项目单元测试配置资源文件位置 target:项目打包后文件所在位置
3. Maven约定优于配置
超级POM:任何一个Maven项目都隐式地继承自一个超级POM,这有点类似于任何一个Java类都隐式地继承于Object类。因此,大量超级POM的配置都会被所有Maven项目继承,这些配置也就成为了Maven所提倡的约定。 对于Maven3,超级POM在文件 $ MAVEN_HOME/lib/maven-moae-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路径下。
首先超级POM定义了仓库及插件仓库,两者的地址都为中央仓库 http://repo1.maven.org/maven2,并且都关闭了SNAPSHOT的支持。这也就解释了为什么Maven默认就可以按照需要从中央仓库下载构件。
依次定义了项目的主输出目录、主代码输出目录、最终构件的名称格式、测试代码输出目录、主源码目录、脚本源码目录、测试源码目录、主资源目录和测试资源目录。这就是Maven项目结构的约定。
二、坐标和依赖
1. Maven坐标
Maven通过groupld、artifactld、version三个变量来唯一确定一个具体的依赖(俗称GAV)
2. Maven依赖配置
- groupld,artifactld,version:基本坐标。
- type:依赖类型,对应项目坐标定义packaging,大部分情况下不需要声明。
3. Maven依赖范围
- compile:编译依赖范围,在编译,测试,运行时都需要,依赖范围默认值
- test:测试依赖范围,测试时需要。编译和运行不需要,如junit
- provided:已提供依赖范围,编译和测试时需要。运行时不需要,如servlet-api
- runtime:运行时依赖范围,测试和运行时需要。编译不需要,例如面向接口编程,JDBC驱动实现jar
- system:系统依赖范围。本地依赖,不在maven中央仓库,结合systemPath标签使用
- import:该范围的依赖只在dependencyManagement元素下才有效果,使用该范围的依赖通常指向一个POM,作用是将目标POM中的
- dependencyManagement配置导入并合并到当前POM的dependencyManagement元素中。
Maven dependencyManagement
- 只能出现在父pom里
- 统一版本号
- 只是依赖声明,并不直接依赖,需要时在子项目中在声明要使用依赖的GA信息,V信息可以省略
- mvn dependency:tree 会列出依赖关系树及各级依赖关系
- mvn dependency:analyze 分析依赖关系
4. POM的继承
抽取不同项目的重复配置,方便版本控制。
三、Maven仓库
得益于坐标机制,任何Maven项目使用任何一个构件的方式都是完全相同的。在此基础上,Maven可以在某个位置统一存储所有Maven项目共享的构件,这个统一的位置就是仓库。 实际的Maven项目将不再各自存储其依赖文件,它们只需要声明这些依赖的坐标,在需要的时候(例如,编译项目的时候需要将依赖加入到classpath中) ,Maven会自动根据坐标找到仓库中的构件,并使用它们。
1. Maven仓库分类
对于Maven来说,仓库只分为两类:本地仓库和远程仓库。 当Maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用; 如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用。 如果本地仓库和远程仓库都没有需要的构件,Maven就会报错。
中央仓库是Maven核心自带的远程仓库,它包含了绝大部分开源的构件。在默认配置下,当本地仓库没有Maven需要的构件的时候,它就会尝试从中央仓库下载。 私服是另一种特殊的远程仓库,为了节省带宽和时间,应该在局域网内架设一个私有的仓库服务器,用其代理所有外部的远程仓库。内部的项目还能部署到私服上供其他项目使用。 除了中央仓库和私服,还有很多其他公开的远程仓库,常见的有http://Java.net Maven库(http:lldownload.java.netlmaven/2/l)和JBoss Maven库(http:http://llrepository.jboss.com/maven2/l)等。
本地仓库在settings.xml文件定义:
私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构f的的医:”管a睿私服上之后,再为Maven构件,则从外部的还程库致经注1冰鲰合库下载到的构件也的下载请求提供服务。此外,一些无法从外部仓库下载到的构件也能从本地上传到私服上供大家使用。
2. Maven远程仓库配置
元素updatePolicy用来配置Maven从远程仓库检查更新的频率,默认的值是daily,表示Maven每天检查一次。其他可用的值包括: never—从不检查更新;always—每次构建都检查更新;interval: X—每隔X分钟检查一次更新(X为任意整数)。 元素checksumPolicy用来配置Maven检查检验和文件的策略。当构件被部署到Maven仓库中时,会同时部署对应的校验和文件。在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败了呢?当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息,其他可用的值包括:fail--Maven遇到校验和错误就让构建失败;ignore--使Maven完全忽略校验和错误。
3. Maven仓库验证
大部分远程仓库无须认证就可以访问,但有时候出于安全方面的考虑,我们需要提供认证信息才能访问一些远程仓库。例如,组织内部有一个Maven仓库服务器,该服务器为每个项目都提供独立的 Maven仓库,为了防止非法的仓库访问,管理员为母个仓库提了一组用户名及密码。这时,为了能让Maven访问仓库内容,就需要配置认证信息。
4. Maven快照与镜像
项目依赖快照版本会在每次构建时自动拉取最新的快照版本。 快照版本只应该在组织内部的项目或模块间依赖使用,因为这时,组织对于这些快照版本的依赖具有完全的理解及控制权。项目不应该依赖于任何组织外部的快照版本依赖,由于快照版本的不稳定性,这样的依赖会造成潜在的危险。也就是说,即使项目构建今天是成功的,由于外部的快照版本依赖实际对应的构件随时可能变化,项目的构建就可能由于这些外部的不受控制的因素而失败。
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。换句话说,任何一个可以从仓库Y获得的构件,都能够从它的镜像中获取。 配置Maven镜像:
<mirrorOf>的值为central,表示该配置为中央仓库的镜像, 任何对于中央仓库的请求都会转至该镜像,用户也可以使用同样的方法配置其他仓库的镜像。另外三个元素id、name、url与一般仓库配置无异,表示该镜像仓库的唯一标识符、名称以及地址。类似地,如果该镜像需要认证,也可以基于该id配置仓库认证。
四、Maven生命周期
Maven的生命周期就是为了对所有的构建过程进行抽象和统一。 Maven从大量项目和构建工具中学习和反思,然后总结了一套高度完善的、易扩展的生命周期。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。也就是说,几乎所有项目的构建,都能映射到这样一个生命周期上。 Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作,在Maven的设计中,实际的任务(如编译源代码)都交由插件来完成。这种思想与设计模式中的模板方法(Template Method)非常相似。
1. Maven三套生命周期
Maven拥有三套完全独立的生命周期,它们分别为:clean,default,site。 clean生命周期的目标是清理项目; default生命周期的的目的是构建项目; site生命周期的目的是建立项目站点。
2. clean生命周期
1) pre-clean执行一些清理前需要完成的工作。 2) clean清理上一次构建生成的文件。 3) post-clean执行一些清理后需要完成的工作。
3. default生命周期
validateinitialize generate-sources process-sources处理项目主资源文件。一般来说,是对 srclmain/resources目录的内容进行变量替换等工作后,复制到项目输出的主classpath目录中。 generate-resources process-resources compile编译项目的主源码。一般来说,是编译srclmainljava目录下的Java文件至项目输出的主classpath目录中。 process-classes generate-test-sources
process-test-sources处理项目测试资源文件。一般来说,是对srcltest/resources目录的内容进行变量替换等工作后,复制到项目输出的测试classpath目录中。 generate-test-resourcesprocess-test-resources test-compile编译项目的测试代码。一般来说,是编译src/testljava目录下的Java文件至项目输出的测试classpath目录中。 process-test-classes test使用单元测试框架运行测试,测试代码不会被打包或部署prepare-package package接受编译好的代码,打包成可发布的格式,如JAR。
pre-integration-testintegration-test post-integration-testverify install将包安装到Maven本地仓库,供本地其他Maven项目使用。deploy将最终的包复制到远程仓库,供其他开发人员和Maven项目使用。
4. site生命周期
pre-site执行一些在生成项目站点之前需要完成的工作。 site生成项目站点文档。 post-site执行一些在生成项目站点之后需要完成的工作。 site-deploy将生成的项目站点发布到服务器上。
5. 插件绑定
对于插件本身,为了能够复用代码,它往往能够完成多个作 maven-dependency-pj芙在的光用依赖;它能够列出项目的依赖.够分析项目依赖,帮助找出潜在的无用依赖;它能够列出项目的依赖树,帮助万们如稳一个独立的插件显价酯整集在一个插件里,每个划每个这样的功能编写一个独立的插件显然是不可取的,因为后有很多可以复用的代码,因此,这些功能聚集在一个插件里,每个功能就是一个插件目标。
生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务。例如项目编译这一任务,它对应了default生命周期的compile这一阶段,而maven-compiler-plugin这一插件的compile目标能够完成该任务。
为了能让用户几乎不用任何配置就能构建Maven项目,Maven在核心为一些主要的生命周期阶段绑定了很多插件的目标,当用户通过命令行调用生命周期阶段的时候,对应的插件目标就会执行相应的任务。