坐标和依赖是任何一个构件在Maven世界中的逻辑表达方式;而构件的物理表示方式是文件,Maven通过仓库来统一管理这些文件
基本概念:
构件
在Maven世界中,任何一个依赖、插件或者项目构建的输出,都可以称为构件。
如依赖log4j-1.2.15.jar是一个构件,插件maven-compiler-plugin-2.0.2.jar是一个构件。
任何一个构件都有一组坐标唯一标识
仓库
得益于坐标机制,任何Maven项目使用任何一个构件的方式都是完全相同的,在此基础上,
Maven可以在某个位置统一存储所有Maven项目共享的构件
这个统一的位置就是仓库
实际的Maven项目将不再各自存储其依赖文件,它们只需要声明这些依赖的坐标,
在需要的时候(如编译项目的时候需要将依赖加入到classpath中) ,
Maven会自动根据坐标找到仓库中的构件,并使用它们。
为了实现重用,项目构建完毕后生成的构件也可以安装或者部署到仓库中,供其他项目使用。
仓库布局方式:
任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径。
如log4j:log4j:1.2.16这一依赖,其对应的仓库路径为log4j/log4j/1.2.16/log4j-1.2.16.jar
该路径与坐标的大致对应关系为:groupId/artifactId/version/artifactId-version.packaging
Maven仓库是基于简单文件系统存储的
仓库的分类:
对于Maven来说,仓库只分为两类:本地仓库和远程仓库。
当Maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用,
如果本地仓库不存在此构件或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用。如果本地仓库和远程仓库都没有需要的构件,Maven就会报错。
特殊的远程仓库:
中央仓库:Maven核心自带的远程仓库,它包含了绝大部分开源构件,
在默认配置下,当本地仓库没有Maven需要的构件的时候,
它就会尝试从中央仓库下载。
私服:为了节省带宽和时间,应该在局域网内架设一个私有的仓库服务器,
用其代理所有外部的远程仓库,内部的项目还能部署到私服上供其他项目使用。
其他公共库:很多其他公共的远程仓库,
常见的有:Java.net Maven库http://download.java.net/maven/2/
JBoss Maven库 http://repository.jboss.org/maven2
本地仓库:
一般来说,在Maven项目目录下,没有诸如lib/这样用来存放依赖文件的目录。当Maven在执行编译或测试时,如果需要使用依赖文件,
它总是基于坐标使用本地仓库的依赖文件
默认情况下,每个用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录。
一个构件只有在本地仓库中之后,才能由其他Maven项目使用,那么构件如何进入到本地仓库中呢?
1:最常见的是依赖Maven从远程仓库下载到本地仓库中。
2:将本地项目的构件安装到Maven仓库中。
安装好Maven后,如果不执行任何Maven命令,本地仓库目录是不存在的。当用户输入第一条Maveen命令之后,Maven才会创建本地仓库,
然后根据配置和需要,从远程仓库下载构件到本地仓库
中央仓库:
由于最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件。中央仓库就是这
样一个默认的远程仓库,Maven的安装文件自带了中央仓库的位置 http://repo.maven.apache.org/maven2。
D:\Program\maven\lib\maven-model-builder-3.0.4.jar中的pom.xml
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>http://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
包含这段配置的文件是所有Maven项目都会继承的超级POM,这段配置使用id central对中央仓库进行唯一标识
它使用default仓库布局(对于Maven 1的仓库,使用legacy的layout),snapshots的enabled的值为false,表
示不从该中央仓库下载快照版本的构件
中央仓库包含了这个世界上绝大多数流行的开源Java构件,以及源码、作者信息、SCM、信息、许可证信息等
私服
私服是一种特殊的远程仓库,这是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven
用户使用。当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存
在私服上之后,再为Maven的下载请求服务。此外,一些无法从外部仓库下载的构件也能从本地上传到私服上供大家使用。
私服的好处:
1:节省自己的外网带宽,减少组织自己的开支
2:加速Maven构建。Maven的一些内部机制(如快照更新检查)要求Maven在执行构建的时候不停地检查远程仓库数据。
3:部署第三方构件(由于版权因素不能发布到公共仓库(如Oracle的JDBC驱动),建立私服之后,便可以将这些构件部署到这个
内部的仓库中,供内部的Maven项目使用。
4:提高稳定性,增加控制。Maven构建高度依赖于远程仓库,使用私服,即使Internaet不稳定或暂时没有Internet连接,
由于私服中已经缓存了大量构件,Maven也仍然可以正常运行。此外,一些私服软件(如Nexus)还提供了很多额外的功能,
如权限管理、RELEASE/SNAPSHOT区分等,管理员可以对仓库进行一些更高级的控制。
5:降低中央仓库的负荷。
远程仓库的配置:
仓库信息可以直接配置在pom文件中
<project>
...
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.org/maven2</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
...
</project>
在repositories元素下,可以使用repository子元素声明一个或多个远程仓库。任何一个仓库声明的id必须是唯一的
一般来说,配置的仓库地址都基于http协议
针对releases和snapshots来说,除了enabled子元素,还包含另外两个子元素
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore></checksumPolicy>
元素updatePolicy用来配置Maven从远程仓库检查更新的频繁,
默认值为daily,表示第天检查一次,其他值如下:
never:从不检查更新
always:每次构建都检查更新
interval:X:每隔X分钟检查一次更新(X为任务整数)
元素checksumPolicy用来配置Maven检查检验和文件的策略,当构件被部署到Maven仓库中时,会同时部署对应的校验和文件。
在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败,根据此值进行处理
默认值为warn,Maven会在执行构建时输出警告信息
fail: 遇到校验或错误就让构建失败
ignore:完全忽略校验和错误。
远程仓库的认证
<server>
<id>deploymentRepo</id>
<username>repouser</username>
<password>repopwd</password>
</server>
认证信息必须配置在settings.xml文件中。其中id必须与POM中需要认证的repository元素的id完全一致,换句话说,正是这个id将认证信息
与仓库配置联系在了一起。
部署至远程仓库
<distributionManagement>
<repository>
<id>69releases</id>
<name>server69 releases repository</name>
<url>http://172.168.27.69/data/repositories/releases</url>
</repository>
<snapshotRepository>
<id>60snapshots</id>
<name>server69 snapshots repository</name>
<url>http://172.168.27.69/data/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
往远程仓库部署构件的时候,往往需要认证。
在命令行运行 mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,
则部署到快照版本仓库地址,否则就部署到发布版本仓库地址。
快照版本
在Maven的世界中,任何一个项目或者构件都必须有自己的版本。
针对快照版本,如模块A的2.1-SNAPSHOT,发布到私服中,在发布的过程中,Maven会自动为构件打上时间戳,比如2.1-20130208.093011-13,就
表示2013年2月8日9点30分11秒的第13次快照,有了该时间戳,Maven就能随时找到仓库中该构件2.1-SNAPSHOT版本最新的文件。
所以其他模块如B针对此模块A的2.1-SNAPSHOT的依赖,在构建B项目的时候,Maven会自动从仓库中检查模块A的2.1-SNAPSHOT的最新构件
当发现有更新时便进行下载,默认情况下,Maven每天检查一次更新
也可以使用命令行-U参数强制让Maven检查更新,如mvn clean install -U
快照版本只应该在组织内部的项目或模块间依赖使用,因为这时,组织对于这些快照版本的依赖具有完全的理解及控制权。
项目不应该依赖于任何组织外部的快照版本依赖。
从仓库解析依赖的机制
当本地仓库没有依赖构件的时候,Maven会自动从远程仓库下载;当依赖版本为快照版本的时候,Maven会自动找到最新的快照。
依赖解析机制可以概括如下:
1:当依赖的范围是system的时候,Maven直接从本地文件系统解析构件。
2:根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件,如果发现相应构件,则解析成功
3:在本地仓库不存在相应构件的情况下,如果依赖的版本是显式的发布版本构件,如1.2,2.1-beta-1等,则遍历所有的远程仓库,
发现后,下载并解析使用
4:如果依赖的版本是RELEASE或LATEST,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/maven-metadata.xml,
将其与本地仓库的对应无数据合并后,计算出RELEASE或者LATEST真实的值,然后基于这个真实的值检查本地和远程仓库
5:如果依赖的版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/maven-metadata.xml,
将其与本地仓库的对应无数据合并后,得到最新快照版,然后基于该值检查本地仓库,或者从远程仓库下载
6:如果最后解析得到的构件版本是时间戳格式的快照,如1.4.1-2013092312.121450-121,则复制其时间戳格式的文件至非时间戳格式,如
SNAPSHOT,并使用该非时间戳格式的构件。
当依赖的版本不明晰的时候,如RELEASE、LATEST、SNAPSHOT,Maven就需要基于更新远程仓库的更新策略来检查更新。
只有仓库开启了对于发布版本的支持时,才能访问该仓库的发布版本构件信息,对于快照版本也是同理;
RELEASE、LATEST版本分别对应了仓库中存在的该构件的最新发布版本和最新版本(包含快照),而这两个“最新”是基于
groupId/artifactId/maven-metadata.xml计算出来的
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-archetype-plugin</artifactId>
<versioning>
<latest>2.2</latest>
<release>2.2</release>
<versions>
<version>1.0-alpha-3</version>
<version>1.0-alpha-4</version>
<version>1.0-alpha-7</version>
<version>2.0-alpha-1</version>
<version>2.0-alpha-2</version>
<version>2.0-alpha-3</version>
<version>2.0-alpha-4</version>
<version>2.0-alpha-5</version>
<version>2.0</version>
<version>2.1</version>
<version>2.2</version>
</versions>
<lastUpdated>20111123122038</lastUpdated>
</versioning>
</metadata>
Maven通过合并多个远程仓库及本地仓库的元数据,就能计算出基于所有仓库的latest和Release分别是什么,然后再解析具体的构件
需要注意的是:在依赖声明中使用LATEST和RELEASE是不推荐的做法,因为Maven随时都可能解析到不同的构件。且Maven不会明确告诉
用户这样的变化。当这种变化造成构建失败的时候,发现问题会变得比较困难。
当依赖的版本设为快照版本的时候,Maven也需要检查更新,这时,Maven会检查仓库元数据groupId/artifactId/maven-metadata.xml
最后,仓库元数据并不是永远正确的,有时候当用户发现无法解析某些构件,或者解析得到错误构件的时候,就有可能是出现了仓库
元数据错误,这时就需要手工地,或者使用工具(如Nexus)对其进行修复
镜像
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像,即任何一个可以从仓库Y获得的构件,都能够从它的镜像中获取
如http://maven.net.cn/content/groups/public 是中央仓库http://repo.maven.org/maven2在中国的镜像
关于镜像的一个更为常见的用法是结合私服。由于私服可以代理任何外部的公共仓库(包括中央仓库),因为对于组织内部的Maven用户来说,使用一个
私服地址就等于使用了所有需要的外部仓库,这可以将配置集中到私服,从而简化Maven本身的配置
在这种情况下,任何需要的构件都可以从私服获得,私服就是所有仓库的镜像。
<mirror>
<id>internal-repository</id>
<mirrorOf>*</mirrorOf>
<name>Internal Repository Manager</name>
<url>http://172.168.27.69/maven2/</url>
</mirror>
<mirrorOf>*</mirrorOf>:匹配所有远程仓库,任何对于远程仓库的请求都会被转至http://172.168.27.69/maven2/
<mirrorOf>external:*</mirrorOf>:匹配所有远程仓库,使用localhost、file://协议的除外,即匹配所有不在本机上的远程仓库
<mirrorOf>repo1,repo2</mirrorOf>:匹配repo1,repo2两个仓库
<mirrorOf>*,!repo1</mirrorOf>:匹配所有远程仓库,repo1除外
注意:由于镜像仓库完全屏蔽了镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。
仓库搜索服务:
Sonatype Nexus http://repository.sonatype.org
jarvana http:www.jarvana.com/jarvana
mvnbrowser http://www.mvnbrowser.com
mvnrepository http://mvnrepository.com