第6章 仓库

maven中的构件构件成功后,以文件的方式保存在磁盘中,maven通过仓库来管理这些文件。

何为maven仓库

在maven中,任何一个依赖、插件、或者项目的构建的输出,都可以称之为构件。构件生成后,需要存储到一个指定的位置,我们称之为仓库,仓库根据指定的规则对maven构件进行管理。仓库中存储了大量的构件,搭建项目时,可以直接从仓库中获取所需要的构件。

仓库的布局

每个构件都有唯一的坐标,maven仓库根据坐标和对应的规则来生成构建唯一的存储路径。对应规则如下:

groupId/artifactId/version/artifactId-version[-classifier].packaging

maven仓库布局源码如下:

private static final char PATH_SEPARATOR = "/";
private static final char GROUP_SEPARATOR = ".";
private static final char ARTIFACT_SEPARATOR = "-";
public String pathOf(Artifact artifact)
{
    ArtifactHandler artifactHandler = artifact.getArtifactHandler();
    StringBuffer path = new StringBuffer(128);
    path.append(formatAsDirectory(artifact.getGroupId())).append(PATH_SEPERATOR);
    path.append(artifact.getArtifactId()).append(PATH_SEPERATOR);
    path.append(artifact.getBaseVersion()).append(PATH_SEPERATOR);
    path.append(artifact.getArtifactId()).append(ARTIFACT_SEPERATOR).append(artifact.getVersion());
    if(artifact.hasClassifier())
    {
        path.append(ARTIFACT_SEPERATOR).append(artifact.getClassifier());
    }
    
    if(artifactHandler.getExtension() != null && artifactHandler.getExtension().length > 0)
    {
        path.append(GROUP_SEPARATOR).append(artifactHandler.getExtension());
    }
    
    return path.toString();
}

private String formatAsDirectory(String directory)
{
    return directory.replace(GROUP_SEPARATOR,PATH_SEPARATOR);
}

下面以一个具体的例子来实例:

groupId    : org.testing
artifactId : testing
version    : 5.8
classifier : jdk15
packaging  : jar

1、基于groupId准备路径,formatAsDirectory()将groupId中的#.#转换为#/#,该实例中将 org.testing转换为 org/testing/。

2、基于artifactId准备路径,在前面的基础之上加上artifactId及一个路径分隔符,该实例中为org/testing/testing/。

3、基于版本信息,在前面的基础之上加上version和路径分隔符,该实例中为org/testing/testing/5.8/。

4、基于构件名称,在前面的基础之上加上artifactId、构件分隔符、版本号,该实例中未org/testing/testing/5.8/artifact-5.8,这里使用的artifactId.getVersion(),上一步使用的是artifactId.getBaseVersion(),baseVersion只包含数字。

5、基于classifier,如果构件有classifier,就加上构件分隔符和classifier,该例中为org/testing/testing/5.8/artifact-5.8-jdk5。

6、基于构件的extension,若extension存在,则加上句点分隔符和extension,extension是从artifactHandler获取,artifactHandler是由项目的packagin决定的,可以说packagin决定了构件的扩展名,该例的packaging是jar,因此最终的路径为:rg/testing/testing/5.8/artifact-5.8-jdk5.jar。

maven系统是基于简单文件系统存储的,当遇到一些与仓库相关的问题时,可以很方便的查找相关文件,定位问题。

仓库的分类

对于maven来说,仓库只分为两类:本地仓库和远程仓库。maven根据坐标查找构件,首先会查看本地仓库,如果本地仓库没有,就回去远程仓库查找,如果都没有,maven就会报错。

远程仓库包括中央仓库、私人仓库、其它远程仓库。

中央仓库是maven核心自带的仓库,它包含了绝大部分构件,在默认配置下,当本地库没有构件时,maven从中央仓库下载构件。

私人仓库是一种特殊菜单远程仓库,为了节省带宽和时间,应该在局域网内架设一个私人仓库,用其代理所有的远程仓库,同时内部的项目也可以部署到私人仓库中。

其它远程仓库,除了中央仓库和私人仓库外,还有很多其它公开的远程仓库,比如java.net.maven库(http://download.java.net/maven/2)和jboss maven库(http://repository.jboss.com/maven2)等。

1、本地仓库

maven本地仓库存储目录为.m2/repository/,可以通过设置.m2/settings.xml(默认情况下本地仓库下不存在settings.xml,需要复制maven安装目录$ M2_HOME/conf/settings文件),设置localRepository元素的值为想要的仓库地址,设置如下:

<settings>
    <localRepository>d:\java\maven\repository</localRepository>
</settings>

一个构件只有在本地仓库中存在后,才能被其它maven项目使用,可以使用mvn clean install命令把项目导入到本地仓库中。

2、远程仓库

maven安装成功后,本地仓库是不存在的,只有执行mvn指令后,maven才会生成本地仓库。本地仓库类似书房的概率,远程仓库类似书店的概念,对于一个用户来说,书房只有一个,书店可以存在多个,用户从书店买书后,存放到书房中。

3、中央仓库

由于本地仓库是空的,所以至少需要配置一个默认的远程仓库,才能在执行命令的时候从远程仓库或者构件,这个默认的远程仓库就是中央仓库。maven的安装文件中自带了中央仓库的配置。打开$M2_HOME/lib/maven-model-builder-3.0.jar,在org/apache/maven/model/pom-4.0.0.xml文件配置中,可以看到如下配置:

<project>
    <repositories>
        <repository>
            <id>central>
            <name>maven reporitory test</name>
            <url>http://repo1.maven.rog/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

包含这段配置的文件是所有Maven项目都会继承的超级POM文件。

4、私服

私服是一种特殊的远程仓库,它是搭建在局域网内的仓库服务。私服代理广域网上的远程仓库,供局域网内的用户使用。当maven需要下载构件时,先从私服获取,如果私服不存在,则从远程仓库获取,缓存到私服后,在为本地用户提供服务。同时一些内部项目也可以放置到私服上,为大家提供服务。

graph LR
A[maven用户] --> |下载构件| B[私服]
B[私服] --> |缓存构件| c[远程仓库]

私服的好处:
1、节省外网带宽。

2、加速maven构件。

3、部署第三方构件。

4、提高稳定性、加强控制。

5、降低中央仓库的负荷。

远程仓库的设置

1、远程仓库的配置

远程仓库的设置如下:

<project>
    <repositories>
        <repository>
            <id>jboss</id>
            <name maven jboss repository</name>
            <url>http://repository.jboss.com/maven2/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <layout>default</layout>
        </repository>
    </repositories>
</project>

在repositories元素下,可以声明多个repository,maven自带的中央仓库名称为central,如果其它仓库使用该名字,将会覆盖中央仓库的配置。

layout为default表示仓库基于默认的布局。

releases和snapshots元素非常重要,它们用来控制发布版本和快照版本的下载。enables为true表示支持下载,enables为false表示关闭下载。除了enables子元素外,他们还包含updatePolicy和checksumPolicy两个子元素。

<snapshots>
    <enabled>true</enabled>
    <updatePolicy>daily</updatePolicy>
    <checksumPolicy>ignore</checksumPolicy>
</snapshots>

updatePolicy配置maven从远程仓库检查更新的频率,daily表示每天更新一次,never表示从不更新,always表示每次构建都检查,interval:x表示每隔X分钟就检查一次更新。

checksumPolicy配置表示maven检查文件和配置的策略,当构件被部署到仓库时,同时部署对应的检验和文件,在下载构件时,同时验证检验和文件,如果检验和验证失败,maven要怎么处理,warm表示对检验和验证失败进行警告,fail表示遇到检验和验证失败就组件构件失败,ignore表示忽略检验和验证失败。

2、远程仓库的认证

大部分远程仓库可以直接访问,但是出于安全的考虑,我们需要提供认证信息才能访问一些仓库。仓库认证信息配置在settings.xml中,因为文件需要提交到远程仓库,所以不能配置到pom.xml中,认证信息配置如下:

<settings>
    <servers>
        <server>
            <id>my-repository</id>
            <username>repo-user</username>
            <password>repo-pass</password>
        </server>
    </servers>
</settings>

settings.xml中的server元素的id必须和pom.xml中repository元素的id一致,正是这个id将认证信息和配置信息联系在一起。

3、部署至远程仓库

maven除了能对项目进行编译、测试、打包外,还能降生成的构件部署到仓库中,首先需要在pom.xml中配置远程仓库的配置,具体如下:

<distributionManagement>
    <repository>
        <id></id>
        <name></name>
        <url></url>
    </repository>
    <snapshotRepository>
        <id></id>
        <name></name>
        <url></url>
    </snapshotRepository>
</distributionManagement>

distributionManagement包含repository和snapshotRepository两个子元素,前者表示发布版本的仓库,后者表示快照版本的仓库。往远程仓库发布应用时,往往需要认证,认证方式即在settings中配置server节点,和之前一样。配置正确后,运行mvn clean deploy命令,发布版本到对应的仓库。

快照版本

在maven中任何一个项目都有自己的版本,版本值可能是1.0.0,1.3-alpha-4,2.1-SNAPSHOT或者2.1-20091111.194822。其中1.0.0和1.3-alpha-4是稳定的发布版本,2.1-SNAPSHOT和2.1-20091111.194822是不稳定的快照版本。
快照版本的意义在于,设置为快照版本后,不需要频繁的更改版本号,maven自动在快照版本的每次提交后,添加时间戳,即年月日时分秒,版本号不需要变动,版本随时在变动,而且这种变动对开发方和使用方都是透明的。开发方设置为快照版本后,每次提交,面上的快照版本号都是一样的,maven会自动添加上时间戳来区分每次提交。使用方配置了快照版本后,maven自动根据时间戳获取最新的版本。因为快照版本的不稳定性,快照版本只应该在项目内部开发过程中使用,等到功能稳定后,需要发布稳定版本。

从仓库解析依赖的机制

maven是根据怎么的规则解析依赖,并从仓库下载构件的呢,具体如下:
1、当依赖范围为system,maven直接从本地文件系统获取解析构件。

2、根据依赖坐标计算仓库路径后,尝试从本地仓库寻找构件,如果发现相应构件,解析成功。

3、在本地仓库不存在相应的构件后,如果依赖的版本是显示的发布版本构件,如1.2、2.1-beta-1等,则遍历所有的远程仓库后,下载并解析使用。

4、如果依赖的版本是RELEASE或者LATEST,则基于更新策略读取所有远程仓库的元数据文件groupId/artifactId/maven-metadata.xml,将其与本地仓库的对应元数据合并后,得到最新的快照版本的值,然后基于该值检查本地仓库或从远程仓库下载。

5、如果依赖的版本是SNAPSHOT,则基于更新策略读取所有远程仓库的元数据文件groupId/artifactId/version/maven-metadata.xml,将其与本地的元数据合并后,然后基于该值检查本地仓库或从远程仓库下载。

6、如果最后解析得到的构件版本是时间戳格式的快照,则复制其时间戳格式的文件为非时间戳格式,如SNAPSHOT,并使用该非时间戳格式的文件。

当依赖的版本不明晰的时候,如release、latest和snapshot,maven就需要基于更新远程仓库的策略来检查更新,有一些配置与此有关,首先是 和 ,只有仓库开启了对于发布版本的支持时,才能访问该版本相关的构件,其次要注意元素,该元素指定了版本更新的频率,包括每日检查更新、永远检查更新、从不检查更新、自定义时间间隔更新。最后,用户还可以在命令行中加入-U参数,强制检查更新。

releas和latest版本分别对应了仓库中存在该构件的最新发布版本和最新版本(包含SNAPSHOT),而这两个最新是基于groupId/artifactId/maven-metadata.xml计算出来的,配置如下:

<?xml version="1.0" encoding="utf-8"?>
<metadata>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compile-plugin</artifactId>
    <versioning>
        <latest>1.4.2-SNAPSHOT</latest>
        <release>1.4.0</release>
        <verions>
            <version>1.3.5</version>
            <version>1.4.0</version>
            <version>1.4.1-SNAPSHOT</version>
            <version>1.4.2-SNAPSHOT</version>
        </versions>
        <lastUpdated>20181107210504</lastUpdated>
    </versioning>
</metatada>

xml中列出了仓库中存在的该构件的所有的版本,latest指向了最新的那个版本,即1.4.2-SNAPSHOT,release指向了最新的发布版本,即1.4.0。在依赖声明中,不建议使用release和latest配置,因为maven随时都可能解析到不同的版本,导致版本不稳定。

当依赖版本设置为快照版本时,maven也需要检查更新,此时maven会检查仓库元数据groupId/artifactId/version/maven-metadata.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<metadata>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-help-plugin</artifactId>
    <version>1.1.1-SNAPSHOT</version>
    <versioning>
        <snapshot>
            <timestamp>20181108.063222</timestamp>
            <buildNumber>15</buildNumber>
        </snapshot>
        <lastUpdated>20181108063222</lastUpdated>
    </versioning>
</metadata>

xml中snapshot元素包含timestamp和buildNumber两个子元素,代表构件时间和构件次数,基于这两个元素可以得到该仓库中此构件的最新构件版本实际为1.1.1-20181108.063222-15,通过合并本地仓库和远程仓库的元数据,maven可以获取所有仓库中该构件的最新版本。

镜像

如果仓库X可以提供仓库Y的所有内容,那么X是Y的镜像。镜像往往可以提供比中央仓库更快的服务,因此可以配置镜像来替代中央仓库,编辑settings.xml,配置代码如下:

<settings>
    <mirrors>
        <mirror>
            <id>maven.net.cn</id>
            <name>central repository mirror</name>
            <url>http://maven.net.cn/content/groups/public/</url>
            <mirrorOf>central</mirrorOf>
        </mirror>
    </mirrors>
<settings>

mirrorOf为central表明配置的是中央仓库的镜像,任何对于中央仓库的请求会转至该镜像。关于镜像的例外一个用法是结合私服,由于私服可以代理任何外部的公共仓库,对于内部用户来说,使用了私服就等于使用了所有的外部仓库。配置如下:

<settings>
    <mirros>
        <mirro>
            <id></id>
            <name></name>
            <url></url>
            <mirrorOf>*</mirrorOf>
        </mirror>
    </mirros>
</settings>

匹配所有远程仓库。
external: 匹配所有原创仓库,本地的除外,即匹配所有不在本机上的远程仓库。
repo1,repo2 匹配仓库repo1,repo2,多个仓库之间以,分隔。
*,!repo1 匹配所有远程仓库,repo1除外,使用感叹号来排除仓库。

仓库搜索服务

在使用maven开发过程中,如果寻找依赖,也是个问题,下面介绍几种常见的公共maven仓库搜索服务。

Sonatype Nexus

http://repositroy.sonatype.rog/ 打开比较慢。

jarvana

http://www.jarvana.com/jarvana/ 网址打不开

MVNbrowser

http://www.mvnbrowser.com

MVNrepository

http://mvnrepository.com 界面比较清新

上面介绍的四种搜索服务都代理了主流的maven仓库,如center,jboss,java.net等。

小结

本章深入阐述了maven仓库的概念,包括仓库的由来、仓库的布局、仓库的类型、远程仓库、仓库的解析依赖机制、镜像、搜索服务等功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值