2

(五)Maven仓库

Maven仓库

在Maven世界中,任何一个依赖、插件或者项目构建的输出,都可以成为构件(jar、war包等)。
Maven在某个位置上统一存储所有Maven项目共享的构件,即为Maven仓库
Maven项目不用各自存储依赖文件,只需声明依赖的坐标,在需要时(编译、运行、打包),Maven会自动根据坐标找到Maven仓库中的构件,并使用它们。

仓库的布局

在Maven世界中,任何一个构件都有其唯一的坐标,通过坐标可以定义其在仓库中的唯一存储路径,即Maven的仓库布局方式。
Maven构件的存储路径为:groupId/artifactId/version/artifactId-version[-classifier].packaging
Ps(个人理解): 仓库的布局方式就是定义了坐标与构件路径的对应关系,即如何通过坐标找到构件。

仓库的分类

对Maven而言,仓库只分为两类,本地仓库、远程仓库。而远程仓库又可细分为中央仓库、私服、其他公共库。
当Maven根据坐标寻找构件时,首先查看本地仓库,如果不存在,Maven就会去远程仓库查找并下载到本地文件。如果都没有,Maven就会报错。分类如下图
clipboard.png

1 本地仓库

通常Maven项目目录下,没有诸如lib/这样存放依赖文件的目录,Maven总是基于坐标使用本地仓库的依赖文件。
默认情况下,不论是Windows还是Linux,本地仓库的路径都为~/.m2/repository(~ 是用户目录)
更改本地仓库路径:~/.m2/settings.xml,设置localRepository元素的值。
如:

<settings>
    ...
    <localRepository>D:\java\repository</localRepository>
    ...
</settings>

安装构件到本地仓库:
1)mvn clean install:构建项目输出文件并安装到本地仓库
2)mvn install:install-file -Dfile=x -DgroupId=x -DartifactId=x -Dversion=x -Dpackaging=x
Dfile待安装构建路径;DgroupId、DartifactId、Dversion、Dpackaging声明其在仓库中的坐标

2 远程仓库

安装好Maven后,如果不执行任何Maven命令,本地仓库目录是不存在的。当用户输入第一条Maven命令之后,Maven才会创建本地仓库,然后根据配置和需要,从远程仓库下载构件至本地仓库。
Maven本地仓库只有一个,但可以配置多个远程仓库
好比本地仓库是书房,远程仓库是书店,当用户需要看一本书时,如果在书房中没找到,就到书店购买并放回书房。通常一个人只有一个书房,但外面的书店有很多。

3 中央仓库

由于原始的本地仓库是空,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令时下载到需要的构件。
中央仓库就是这样一个默认远程仓库。在Maven安装文件中自带了中央仓库的配置。
在Maven安装目录/lib/maven-model-builder-xx.jar中访问路径org/apache/maven/model/pom-4.0.0.xml。
Ps(个人理解):pom-4.0.0.xml 与 pom.xml中<modelVersion>4.0.0</modelVersion> 应该存在某些关联
pom-4.0.0.xml是所有Maven项目都会继承的超级POM,查看该文件,可以找到中央仓库配置。

<repositories>
    <repository>
        <id>central</id>
        <name>Central Repository</name>
        <url>https://repo.maven.apache.org/maven2</url>
        <layout>default</layout>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

4 私服

私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务。私服代理广域网上的远程仓库,供局域网内的Maven用户使用。
clipboard.png

上图展示了组织内部使用私服的情况,即使在一台直接连入Internet的个人机器上使用Maven,也应本地建立私服。
建立私服的优点:

节省自己的外网带宽 消除对外的重复构件下载,降低外网带宽的压力。
加速Maven构建 不停的请求外部仓库十分耗时,Maven的一些内部机制(如快照更新检查)要求Maven在执行构建时不停地检查远程仓库数据,当项目配置很多外部远程仓库时,构建速度大大降低。使用私服,Maven只需检查局域网内私服数据,提高构建速度。
部署第三方构建 安装组织内部生成的私有构件到私服,供内部Maven用户
提高稳定性,增强控制 Maven构建高度依赖于远程仓库,Internet不稳定,Maven构建也会变得不稳定,甚至失败,使用私服后,即使暂时没有Internet,由于私服缓存了很多构件,Maven也能正常运行。此外,很多私服(如Nexus)软件还提供了额外的功能,如权限管理,RELEASE/SNAPSHOT区分等
降低中央仓库的负荷 使用私服可以避免很多对中央仓库的重复下载。

远程仓库的配置

在POM中配置远程仓库

<repositories>
    <repository>
        <id>...</id>    <!-- 仓库唯一标识,重复会覆盖上一个远程仓库 -->
        <name>...</name>    <!-- 仓库名称 -->
        <url>...</url>    <!-- 仓库地址 -->
        <releases>    <!-- 重要!控制Maven对于发布版本构件的下载 -->
            <enabled>...</enabled>    <!-- true/false 控制发布版本构件的下载 -->
            <updatePolicy>...</updatePolicy>    <!-- 更新策略 daily(默认,每天一次)、never(从不)、always(每次构建)、interval:X(间隔X分钟) -->
            <checksumPolicy>...</checksumPolicy>    <!-- 检查检验和文件的策略 warn(默认,校验失败,输出警告信息)、fail(校验失败,无法完成构建)、ignore(忽略校验失败) -->
        </releases>
        <snapshots>    <!-- 重要!控制Maven对于快照版本构件的下载 -->
            <enabled>...</enabled>    <!-- true/false 控制快照版本构件的下载 -->
            <updatePolicy>...</updatePolicy>    <!-- 更新策略 daily(默认,每天一次)、never(从不)、always(每次构建)、interval:X(间隔X分钟) -->
            <checksumPolicy>...</checksumPolicy>    <!-- 检查检验和文件的策略 warn(默认,校验失败,输出警告信息)、fail(校验失败,无法完成构建)、ignore(忽略校验失败) -->
        </snapshots>
        <layout>default</layout>    <!-- 仓库布局方式 -->
    </repository>
    ...
</repositories>

1 远程仓库的认证

大部分远程仓库无须认证就可访问,但有时出于安全方面考虑,我们需要提供认证信息才能访问一些远程仓库。
配置认证信息必须配置在settings.xml中,因为POM往往提交到代码仓库中供所有成员访问,显然,本地settings.xml更安全

<settings>
    ...
    <servers>
        <server>
            <id>..</id>    <!-- 需要提供认证信息才能访问的远程仓库ID -->
            <username>...</username>    <!-- 用户名 -->
            <password>...</password>    <!-- 密码 -->
        </server>
    </servers>
    ...
</settings>

2 部署至远程仓库

1) 编辑项目的pom.xml

<project>
    <distributionManagement>
        <repository>    <!-- 指定发布版本构件的仓库 -->
            <id>...</id>
            <name>...</name>
            <url>...</url>
        </repository>
        <snapshotRepository>    <!-- 指定快照版本构件的仓库 -->
             <id>...</id>
            <name>...</name>
            <url>...</url>
        </snapshotRepository>
    </distyibutionManagement>
</project>

2) 往远程仓库部署构件时,往往需要认证。在settings.xml中配置认证信息
3)执行mvn clean deploy,部署到远程仓库

快照版本

在Maven世界中。任何一个项目或者构件都必须有自己的版本,而Maven又将版本分为两种:
发布版本:稳定,格式如:1.0.0、1.3-alpha-4、2.0
快照版本:不稳定,格式如:2.1-SNAPSHOT、2.1-20091214.221414-13

假设:同时开发项目A、B,而项目B依赖于项目A,在项目未正式方布时,开发方案如下
方案一:检出项目A源码进行构建。能获得项目A最新构件,但需要额外的构建操作,而且构建出问题也不好解决,低效
方案二:重复部署项目A,版本号不变。需要清理本地仓库相同版本号的项目A构件,不然无法下载A最新构件
方案三:不停更新版本。需要频繁修改POM文件,同时造成版本号的滥用。
方案四:将项目A的版本设置为快照版本。

Maven在发布项目快照版本时,会自动打上时间戳。如2.1-20091214.221414-13 表示 2009年12月14日22时14分14秒 第13次快照。通过时间戳,Maven就能找到该构件的最新快照版本。
默认情况下,Maven会每天检查一次更新(由仓库配置的updatePolicy控制),也可通过-U命令强制更新,如mvn clean install -U

从仓库解析依赖的机制

当本地仓库没有依赖构件时,Maven会自动从远程仓库下载;当依赖版本为快照版本时,Maven会自动找到最新的快照。其依赖解析机制如下
1)依赖范围是system,Maven直接从本地文件系统解析构件。
2)根据依赖坐标计算仓库路径,Maven直接从本地仓库寻找构件,如果发现相应构件,则解析成功。
3)本地仓库不存在,且依赖版本是显式的发布版本构件(1.0,1.2-beta-1),遍历所有远程仓库,发现后下载并解析使用
4)如果依赖版本是RELEASE和LATEST,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/maven-metadata.xml,将其与本地仓库的对应元数据合并后,计算出RELEASE或LATEST的真实的值,然后基于这个值检查本地和远程仓库。
5)如果依赖版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据groupId/artifactId/version/maven-metadata.xml,将其与本地仓库的对应元数据合并后,得到最新快照版本的值,然后基于该值检查本地仓库和远程仓库。
6)如果最后解析得到的构件版本是时间戳格式的快照,如1.4.1-20091104.121450-121,则复制其时间戳格式文件至非时间戳格式,如SNAPSHOT,并使用该非时间戳格式的构件。

Maven基于更新策略来检查更新,与远程仓库配置中<release>和<snapshot>中的子元素<enable>、<updatePolicy>有关,只有enable为true,才能访问该仓库对应发布版本/快照版本的构件信息,并基于updatePolicy更新策略检查更新,使用-U可以强制更新。
当Maven检查完更新策略,并决定检查依赖版本,就需要检查仓库元数据maven-metadata.xml
基于groupId和artifactId的maven-metadata.xml

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>org.sonatype.nexus</groupId>
  <artifactId>nexus</artifactId>
  <versioning>
    <latest>1.4.2-SNAPSHOT</latest>    <!-- 指向最新版本 -->
    <release>1.4.0</release>    <!-- 指向最新发布版本 -->
    <versions>    <!-- 版本历史记录 -->
      <version>1.3.5</version>
      <version>1.3.6</version>
      <version>1.4.0-SNAPSHOT</version>
      <version>1.4.0.1-SNAPSHOT</version>
      <version>1.4.1-SNAPSHOT</version>
      <version>1.4.2-SNAPSHOT</version>
    </versions>
    <lastUpdated>20091214221557</lastUpdated>    <!-- 记录最近更新时间 -->
  </versioning>
</metadata>

该XML文件列出仓库中存在的该构件的所有可用的版本,Maven通过合并多个远程仓库及本地仓库的元数据,就能计算出基于所有仓库的latest和release分别是什么,然后再解析具体的构件。
Ps:不推荐依赖声明中使用LATEST和RELEASE,Maven随机解析到不同的构件,当构件发生变化,可能会造成项目构建失败,且不易排查。

当依赖版本是快照版本时,Maven也需要检查更新。
基于groupId、artifactId和version的maven-metadata.xml

<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
  <groupId>org.sonatype.nexus</groupId>
  <artifactId>nexus</artifactId>
  <version>1.4.2-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <timestamp>20091214.221414</timestamp>
      <buildNumber>13</buildNumber>
    </snapshot>
    <lastUpdated>20091214221414</lastUpdated>
  </versioning>
</metadata>

该XML文件的snapshot元素包含timestamp和buildNumber两个元素分别代表这一快照的时间戳和构建号。并由此可以得到该仓库中此快照的最新构件版本实际为1.4.2-20091214.221414-13,通过合并所有远程仓库和本地仓库的元数据,就能知道所有仓库中该构件的最新快照。

最后,元数据并非永远正确,当某些构件无法解析,或解析错误时,需手工或使用工具(如Nexus)对齐进行修复。

镜像

如果仓库X可以提供仓库Y存储的所有内容,那么就可以认定X是Y的一个镜像。
举个例子,http://maven.net.cn/content/g...://repol.maven.org/maven2在中国的镜像,由于地理位置因素,使用该镜像往往能够提供比中央仓库更快的服务。

编辑settings.xml,配置镜像

<settings>
    ...
    <mirrors>
        <mirror>
            <id>...</id>    <!-- 镜像仓库id -->
            <name>...</name>    <!-- 镜像仓库名称 -->
            <url>...</url>    <!-- 镜像仓库地址 -->
            <mirrorOf>...</mirrorOf>    <!-- 被镜像仓库表达式: *(匹配所有远程仓库) -->
        </mirror>
    </mirrors>
    ...
</settings>

mirrorOf元素用来匹配被镜像仓库(有点类似于Servlet的url-pattern表达式),当你要访问的远程仓库id满足mirrorOf表示式时,就会被拦截访问镜像服务器。表达式语法如下:

* 匹配所有远程仓库
external:* 匹配所有远程仓库,localhost除外
a,b 匹配a和b仓库,多个仓库用,隔开
*,!a 匹配所有远程仓库,a除外,使用感叹号将仓库从匹配中排除

仓库搜索服务

使用Maven进行日常开发时,获取依赖需要确切的依赖坐标,通过仓库搜索服务可以根据关键字得到Maven坐标。

Sonatype Nexus http://repository.sonatype.org 提供关键字搜索、类名搜索、坐标搜索、校验和搜索等功能,坐标和构件下载
aliyun Nexus http://maven.aliyun.com 同上,aliyun架设的公共Nexus仓库实例,服务较快
Jarvana http://www.jarvana.com/jarvana 提供基于关键字、类型搜索,坐标,构件下载。还支持浏览构件内部内容和便捷的Java文档浏览功能
MVNbrowser http://www.mvnbrowser.com 只提供关键字搜索,坐标,还可查看构件依赖于那些构件(Dependencies)以及该构件被哪些其他构件依赖(Referenced By)
MVNrepository http://mvnrepository.com 提供关键字搜索,坐标,构件下载,依赖于被依赖关系信息,构件所含信息,还能提供一个简单图表,显示某个构件各版本间的大小变化

roylion
204 声望25 粉丝

读书破万卷