何为仓库

得益于 Maven 的坐标机制,任何 Maven 项目使用构件的方式都是相同的。在此基础上,Maven 可以在某个位置统一存储所有 Maven 项目的构件,这个统一位置就称作「仓库」。

「仓库」中每个构件只需存储一份,所有项目共享,每个项目通过坐标「引用」仓库中的构件。

仓库布局

每一个构件在仓库中都有一个唯一的存储路径,可以通过 Maven 的坐标机制来定位。

格式大致如下:groupId/artifactId/version/artifactId-version-[classifier].packaging,其中 classifier 是可选值,groupId 中的「.」替换成路径符号「/」。

这个路径就是 Maven 坐标值的一个组合,因为在 Maven 中每个构件的坐标是唯一的,那么利用坐标自然就能生成一个唯一的存储路径而无需再另建一套机制增加复杂度。

仓库分类

对于 Maven 来说,仓库只分为两类:本地仓库和远程仓库。在使用构件的时候,Maven 会优先从本地仓库中寻找,如果本地仓库中有就直接使用;如果本地仓库没有,Maven 就会从远程仓库中去查找、下载到本地仓库再使用;如果本地仓库和远程仓库都没有,Maven 就会报错。

本地仓库

Maven 本地仓库就是电脑上的一个目录,默认路径是:~/.m2/repository/。

通过 Maven 的配置文件 settings.xml 可以进行自定义,具体配置如下:

<settings>
    <localRepository>/data/repo</localRepository>
</settings>

远程仓库

Maven 的远程仓库是一定要配置的,否则无法使用,因为本地所有的构件都是在使用时从远程仓库下载的。

但是我们在使用时会发现自己没有配置远程仓库也是能正常使用 Maven 下载构件的。那是因为 Maven 本身自带了一个特殊的远程仓库,就是我们常说的「中央仓库」,地址是:Central Repository。也就是说,在没有配置远程仓库的情况下,默认都是从中央仓库下载的。

除了「中央仓库」,Maven 中还有一个特殊类型的远程仓库,就是「私服」。基本上每个公司都会搭建内部的私服,作用主要有三个:

  1. 代理所有外部远程仓库,统一管理,节省外网带宽和下载时间。顺带统一并减少了每台开发机的远程仓库配置,只需配置私服这一个远程仓库即可。

  2. 内部项目发布到私服上供公司内部共享。

  3. 部署第三方非开源构件。

目前最常用的私服软件是 Nexus。

远程仓库配置

远程仓库有两种配置方式,一种是在 Maven 的 settings.xml 文件中,一种是在项目的 pom.xml 文件中,配置的方式基本一样。settings.xml 文件中只能配置在 <profile> 标签中,pom.xml 文件中有 <profile> 和直接配置两种。

下面是两种配置文件的配置的样例:

settings.xml

<settings>
    <profiles>
        <profile>
            <id>aliyun</id>
            <repositories>
                <repository>
                    <id>aliyun-repo</id>
                    <name>aliyun repo</name>
                    <releases>
                        <enabled>true</enabled>
                        <updatePolicy>daily</updatePolicy>
                        <checksumPolicy>warn</checksumPolicy>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                        <updatePolicy>always</updatePolicy>
                        <checksumPolicy>warn</checksumPolicy>
                    </snapshots>
                    <url>https://maven.aliyun.com/repository/public</url>
                    <layout>default</layout>
                </repository>
            </repositories>
        </profile>
    </profiles>
    <activeProfiles>
        <activeProfile>aliyun</activeProfile>
    </activeProfiles>
</settings>

pom.xml

<project>
    <!-- 直接配置 -->
    <repositories>
        <repository>
            <id>aliyun-pom-repo</id>
            <name>aliyun pom repo</name>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>warn</checksumPolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>warn</checksumPolicy>
            </snapshots>
            <url>https://maven.aliyun.com/repository/public</url>
            <layout>default</layout>
        </repository>
    </repositories>

    <!-- profile 中配置 -->
    <profiles>
        <profile>
            <id>aliyun-pom</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <repositories>
                <repository>
                    <id>aliyun-pom-repo-p</id>
                    <name>aliyun pom repo p</name>
                    <releases>
                        <enabled>true</enabled>
                        <updatePolicy>daily</updatePolicy>
                        <checksumPolicy>warn</checksumPolicy>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                        <updatePolicy>always</updatePolicy>
                        <checksumPolicy>warn</checksumPolicy>
                    </snapshots>
                    <url>https://maven.aliyun.com/repository/public</url>
                    <layout>default</layout>
                </repository>
            </repositories>
        </profile>
    </profiles>
</project>

<repositories> 标签下 <repository> 就是远程仓库的配置,可以配置一个或多个。相关配置含义如下:

  • <id>:是远程仓库的唯一标识,不能重复。

  • <name>:仓库描述,方便人理解。

  • <url>:仓库地址。

  • <layout>:default,表示仓库布局是 maven 2 和 maven 3 的默认布局。

  • <releases>:表示是否开启对发布版本构件的下载

  • <snapshots>:表示是否开启对快照版本构件的下载

  • <enabled>:是否开启,true - 是,false - 否。

  • <updatePolicy>:从远程仓库检查更新的频率,默认值是 daily - 每天检查,还有 never - 从不检查,always - 每次构建检查,interval:X - 每隔 X 分钟检查。

  • <checksumPolicy>:检查校验和文件的策略,校验失败执行的动作,默认值是 warn - 构建时输出警告信息,还有 fail - 使构建失败,ignore - 忽略校验错误。

优先级

  • settings.xml 中配置的远程仓库优先级最高,其次是 pom.xml 中的 <profile> ,最低是 pom.xml 中直接配置。

  • <profiles> 内部定义在后面的 profile 中的远程仓库优先级更高,

  • <repositories> 内部定义在前面的 repository 优先级更高。

镜像

有时候我们配置的远程仓库由于一些原因无法访问或者下载速度很慢;还有的时候我们想把所有远程仓库都集中到一个地方管理,不要在每个项目或者每台机器上的 Maven 里都配置。

对于这两个需求,Maven 的镜像功能就是一个很好的解决方案。在 settings.xml 中添加以下配置:

<settings>
    <mirrors>
        </mirror>
            <id>nexus-repo</id>
            <mirrorOf>*</mirrorOf>
            <name>nexus repo</name>
            <url>http://192.168.55.16:8081/nexus/content/repositories/public</url>
        </mirror>
    </mirrors>
</settings>

这段配置的作用是使用指定的仓库代理所有远程仓库,将从任意远程仓库下载构件这个动作全部转到 <url> 指定的这个仓库中。

在这个镜像仓库配置中,<url> 配置成私服地址就可以解决本节开头提出的两个问题。

如果不配置成私服,配置成其他公共的 Maven 仓库只能解决下载慢的问题,而且要注意 <mirrorOf> 这个配置必须改成具体代理的仓库 id,例如代理中央仓库就配置成这样 <mirrorOf>central</mirrorOf>

为什么呢?

因为你不能确定公共仓库代理了你需要的所有远程仓库(至少私服就没有),有你需要的所有构件。如果缺少某一个构件,那么哪怕你添加了新的远程仓库也是于事无补的,因为添加的新仓库也会被镜像仓库代理,所以非私服的镜像仓库禁止把镜像规则配置成 <mirrorOf>*</mirrofOf>

私服可以自己添加代理的远程仓库,所以私服不存在上面那个问题。

因此,将私服配置成代理所有外部仓库的镜像仓库算是 Maven 使用的一条最佳实践。

认证配置

绝大部分仓库是不需要配置认证的,特别是只用来下载依赖的远程仓库,几乎都是直接访问的,当然也可以添加认证。

但是当我们需要发布自己的项目构件到远程仓库中的时候通常就需要配置认证了,发布这个动作对于远程仓库来说相当于修改,如果谁都能修改仓库内容,那就没有任何安全性可言了。

Maven 中配置仓库认证信息的位置只有 settings.xml 文件这一个。样例如下:

<settings>
    <servers>
        <server>
            <id>nexus_releases</id>
            <username>repouser</username>
            <password>repopwd</password>
        </server>
        <server>
            <id>nexus_snapshots</id>
            <username>repouser</username>
            <password>repopwd</password>
        </server>
    </servers>
</settings>

主要有三个配置,username/password 是账号/密码,很容易理解。

关键是 id 这个配置,这个 id 的值必须与配置的远程仓库的 id 值一致,因为 Maven 就是利用 id 这个配置的值将远程仓库和配置的认证信息关联到一起的。

镜像仓库也可以按照相同的方式配置认证信息。

发布构件

前面说了,私服的其中一个作用是存储公司内部的项目构件,供公司内部共享。

而 Maven 的 deploy 命令就是用来发布项目构件到私服的,但是在执行 mvn clean deploy 这个命令发布之前,需要在项目的 pom.xml 文件中预先配置好私服的地址,样例如下:

    <distributionManagement>
        <repository>
            <id>nexus_releases</id>
            <name>Release Repository</name>
            <url>http://192.168.55.16:8081/nexus/content/repositories/releases/</url>
        </repository>
        <snapshotRepository>
            <id>nexus_snapshots</id>
            <name>Snapshots Repository</name>
            <url>http://192.168.55.16:8081/nexus/content/repositories/snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

发布仓库的配置内容跟之前远程仓库的配置类似,只不过将仓库分成了 <repository> 和 <snapshotRepository> 两种类型,这两类仓库分别用来存储「发布版本」和「快照版本」两类构件。

版本

Maven 的构件版本分为两类,一类是发布版本,一类是快照版本。

发布版本比较容易理解,是项目开发、测试完成后最终生成的稳定版本,发布完之后不能更改,一个发布版本号只能用一次。

快照版本是开发过程中的产物,特点是不稳定,随改随发,改动、发布效率高,版本号以 SNAPSHOT 作为后缀。

为什么会存在快照版本这个机制呢?主要是为了提高开发协作的效率。举个例子:

在开发协作过程中,A 使用 B 提供的快照版本构件进行开发,当出现问题时,只需通知 B 修改再次发布就可以了。B 发布之后,A 直接重新构建项目, 无需修改依赖的版本号,Maven 会自动从私服拉取当前快照版本的最新一版构件(可能会因为私服更新频率设置的问题,导致拉取最新快照版本失败,可以通过手动执行 mvn clean package -U 命令强制更新解决)。然后双方重复这个过程直到联调测试完毕,最终上线前把依赖的快照版本更改为发布版本进行发布。

Maven 提供的这两种类型版本,只要使用得当,既能提高开发协作的效率,又能保证发布版本的稳定。

最后

以上就是我了解的关于 Maven 仓库的内容,希望对大家有帮助,如果有疑问,欢迎大家留言讨论。