7. Maven 使用Nexus创建私服
私服不是 Maven 的核心概念,它仅仅是一种衍生出来的特殊的 Maven 仓库。通过建立自己的私服,就可以降低*仓库负荷、节省外网带宽、加速 Maven 构建、自己部署构件等,从而高效地使用 Maven。
有三种专门的 Maven 仓库管理软件可以用来帮助大家建立私服: Apache Archiva、 JFrog Artifactory 和 Sonatype Nexus。其中, Archiva 是开源的,而 Artifactony 和 Nexus 的核心也是开源的,因此读者可以*选择使用。本章将介绍 Nexus的主要功能,并结合大量图片帮助读者快速地建立起自己的 Maven 私服。
1. 安装 Nexus
Nexus 是典型的 Java Web 应用,自带 Jetty 容器的 Bundle 包。
1.1 下载 Nexus
首先从 https://www.sonatype.com/download-oss-sonatype 下载 nexus-2.14.8-01-bundle.zip。
1.2 Nexus 安装
Nexus 的 Bundle 自带了Jetty 容器,因此用户不需要额外的 Web 容器就能直接启动 Nexus。首先将 Bundle 文件解压,这时就会得到如下两个子目录:
- nexus-2.14.8-01/ :该目录包含了 Nexus 运行所需要的文件,如启动脚本、依赖 jar 包等。
- sonatype-work/ :该目录包含 Nexus 生成的配置文件、日志文件、仓库文件等。
其中,第一个目录是运行 Nexus 所必需的,而且所有相同版本 Nexus 实例所包含的该目录内容都是一样的而第二个目录不是必须的, Nexus 会在运行的时候动态创建该目录,不过它的内容对于各个 Nexus 实例是不一样的,因为不同用户在不同机器上使用的 Nexus 会有不同的配置和仓库内容。当用户需要备份 Nexus 的时侯,默认备份 sonatype-work/ 目录。
在 Windows 下进入 nexus-2.14.8-01/bin/jsw/windows-x86-64 目录运行 install-nexus.bat ,start-nexus.bat 就可以启动 Nexus 服务了。默认的用户名和密码为 admin/admin123。
Nexus 启动有可能出现以下 bug:
-
wrapper | OpenSCManager failed - 拒绝访问。 (0x5)
主要是没有权限。需要以管理员的身份运行。
-
端口冲突
编辑 nexus-2.14.8-01/conf/nexus.properties 文件的 application-port=8081
2. Nexus 的仓库与仓库组
作为 Maven 仓库服务软件,仓库自然是 Nexus 中最重要的概念。 Nexus 包含了各种类型的仓库概念,包括代理仓库、宿主仓库和仓库组等。
2.1 Nexus 内置的仓库
在具体介绍每一种类型的仓库之前,先浏览一下 Nexus 内置的一些仓库。单击 Nexus 界面左边导航栏中的 Repositories 链接,就能看到 Nexus 的内置仓库。这个列表已经包含了所有类型的 Nexus 仓库。从中可以看到仓库有四种类型:group(仓库组)、 hosted(宿主)、 proxy(代理)和 virtual(虚拟)。每个仓库的格式为 maven2 或者 maven1。此外,仓库还有一个属性为 Policy(策略),表示该仓库为发布(Release)版本仓库还是快照(Snapshot)版本仓库。最后两列的值为仓库的状态和路径。maven1 格式的仓库忽略。
-
Maven Central
该仓库代理 Maven *仓库,其策略为 Release,因此只会下载和缓存*仓库中的发布版本构件。 -
Releases
这是一个策略为 Release 的宿主类型仓库,用来部署组织内部的发布版本构件。 -
Snapshots
这是一个策略为 Snapshot 的宿主类型仓库,用来部署组织内部的快照版本构件。 -
3rd party
这是一个策略为 Release 的宿主类型仓库,用来部署无法从公共仓库获得的第三方发布版本构件。 -
Apache Snapshots
这是一个策略为 Snapshot 的代理仓库,用来代理 Apache Maven 仓库的快照版本构件。 -
Public Repositories
该仓库组将上:述所有策略为 Release 的仓库聚合并通过一致的地址提供服务。
2.2 Nexus 仓库分类的概念
为了帮助读者理解宿主仓库、代理仓库和仓库组的概念,图3 用更为直观的方式展现了它们的用途和区别。
从上图中可以看到, Maven 可以直接从宿主仓库下载构件; Maven 也可以从代理仓库下载构件,而代理仓库会间接地从远程仓库下载并缓存构件;最后,为了方便, Maven 可以从仓库组下载构件,而仓库组没有实际内容(图中用虚线表示),它会转向其包含的宿主仓库或者代理仓库获得实际构件的内容。
2.3 创建 Nexus 宿主仓库
要创建一个宿主仓库,首先单击界面左边导航栏中的 Repositories 链接,在右边的面板中,选择 Add,接着在下拉菜单中选择 Hosted Repository,就会看到图 5 所示的配置界面。
-
Repository ID
仓库的 ID -
Repository Name
仓库的名称 -
Repository Type
表示该仓库的类型。 -
Provider
用来确定该仓库的格式。一般来说,选择默认的 Maven2 Repository。 -
Repository Policy
根据自己的需要来配置该仓库是发布版构件仓库还是快照版构件仓库。 -
Default Local Storage Location
表示该仓库的默认存储目录,图中该字段的值为空,待仓库创建好之后,该值就会成为基于 sonate-work 的一个文件路径,如 sonate-work/nexus/story/repository-id/ -
Override Local Storage Location
可以用来配置自定义的仓库目录位置。 -
Access Settings 小组
-
Deployment Policy
用来配置该仓库的部署策略,选项有只读(禁止部署)、关闭重新部署(同一构件只能部署一次)以及允许重新部署。 -
Allow File Browsing
表示是否允许浏览仓库内容,一般选 True。每个仓库(包括代理仓库和仓库组)都有一个 Browse Storage选项卡,用户以树形结构浏览仓库存储文件的内容 -
Include in Search
表示是否对该仓库进行索引并提供搜索。 -
Publish URL
用来控制是否通过 URL 提供服务,如果选 False,当访问该仓库的地址时,会得到 HTP404 Not Found 错误。
-
-
配置中最后的 Not Found Cache TTL
表示当一个文件没有找到后,缓存这一不存在信息的时间。以默认值 14440 分钟(24h)为例,如果某文件不存在,那么在之后的 14440 分钟内,如果 Nexus 再次得到该文件的请求,它将直接返回不存在信息,而不会查找文件系统。这么做是为了避免重复的文件查找操作以提升性能。
2.4 创建 Nexus 代理仓库
首先单击界面左边导航栏中的 Repositories 链接,在右边的面板中,选择 Add,接着在下拉菜单中选择 Proxy Repository,就会看到图 7 所示的配置界面。
仓库的ID、名称、 Provider、 Format、 Policy、默认本地存储位置和覆盖本地存储位置等配置前面都已提过,这里不再赘述。需要注意的是,这里的 Repository Type 的值为 proxy。
对于代理仓库来说,最重要的是远程仓库的地址,即 Remote Storage Location,用户必须在这里输入有效的值。 Download Remote Index 表示是否下载远程仓库的索引,有些远程仓库拥有索引,下载其索引后,即使没有缓存远程仓库的构件,用户还是能够在本地搜索和浏览那些构件的基本信息。 Checksum Policy 配置校验和出错时的策略,用户可以选择忽略、记录警告信息或者拒绝下载。当远程仓库需要认证的时候,这里的的 Authentication 配置就能派上用处。
Access Settings 的配置与宿主仓库类似,在此不再鰲述。 Expiration Settings 较宿主仓库多了 Artifact Max Age 和 Metadata Max Age。其中,前者表示构件缓存的最长时间,后者表示仓库元数据文件缓存的最长时间。对于发布版仓库来说, Artifact Max Age 默认值为 -1,表示构件缓存后就一直保存着,不再重新下载。对于快照版仓库来说, Artifact Max Age 默认值为 1440 分钟,表示每隔一天重新缓存代理的构件。
配置中最后两项为 HTTP Request Settings 和 Override HTTP Proxy Settings,其中前者用来配置 Nexus 访问远程仓库时 HTTP 请求的参数,后者用来配置 HTTP 代理。
2.5 创建 Nexus 仓库组
要创建一个仓库组,首先单击界面左边导航栏中的 Repositories 链链接,在右边的面板中,选择 Add,接着在下拉菜单中选择 Repository Group,就会看到图 8 所示的配置界面。
配置中的 ID、Name 等信息这里不再赘述。需要注意的是,仓库组没有 Release 和 Snapshot 的区别,这不同于宿主仓库和代理仓库。在配置界面中,用户可以非常直观地选择 Nexus 中仓库,将其聚合成一虚拟仓库组。注意:仓库组所包含的仓库的顺序决定了仓库组遍历其所含仓库的次序,因此最好将常用的仓库放在前面,当用户从仓库组下载构件的时候,就能够尽快地访问到包含构件的仓库。
3. 配置 Maven 从 Nexus 下载构件
当需要为项目添加 Nexus 私服上的 public 仓库时,可以按如下代码配置:
<repositories>
<repository>
<id>nexus</id>
<name>Nexus Repository</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>Nexus Repository</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
这样的配置只对当前 Maven 项目有效,在实际应用中,我们往往想要通过一次配置就能让本机所有的 Maven 项目都使用自己的 Maven 私服。这个时候读者可能会想到到 setings.xml 文件,该文件中的配置对所有本机 Maven 项目有效,但是 settings.xml 并不支持直接配置 repositories 和 pluginrepositories。所幸 Maven 还提供了 Profile 机制,能让用户将仓库配置放到 setting.xml 中的 Profile 中,如代码如下所示。
<settings>
<profiles>
<profile>
<id>nexus</id>
<repositories>
<repository>
<id>nexus</id>
<name>Nexus Repository</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>Nexus Repository</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>nexus</activeProfile>
</activeProfiles>
</settings>
该配置中使用了一个 id 为 nexus 的 profile,这个 profile 包含了相关的仓库配置,同时配置中又使用 activeProfile 元素将 nexus 这个 profile 激活,这样当执行 Maven 构建的时候,激活的 profile 会将仓库配置应用到项目中去。
细心的读者可能会注意到, Maven 除了从 Nexus 下载构件之外,还会不时地访问*仓库 central,我们希望的是所有 Maven 下载请求都仅仅通过 Nexus,以全面发挥私服的作用。这个时候就需要借助于 Maven 镜像配置了。可以创建一个匹配任何仓库的镜像镜像的地址为私服,这样, Maven 对任何仓库的构件下载请求都会转到私服中。具体配置如下:
<settings>
<mirrors>
<mirror>
<id>nexus</id>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<profiles>
<profile>
<id>nexus</id>
<properties>
<maven.complie.source>1.8</maven.complie.source>
<maven.complie.target>1.8</maven.complie.target>
</properties>
<repositories>
<repository>
<id>central</id>
<name>Nexus Repository</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Nexus Repository</name>
<url>http://localhost:8081/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>nexus</activeProfile>
</activeProfiles>
</settings>
关于镜像、 profile 及 profile 激活的配置不再赘述,这里需要解释的是仓库及插件仓库配置,它们的 id 都为 central,也就是说,覆盖了超级 POM *仓库的配置,它们的 url 已无关紧要,因为所有请求都会通过镜像访问私服地址。配置仓库及插件仓库的主要目的是开启对快照版本下载的支持,当 Maven 需要下载发布版或快照版构件的时候,它首先检查 central,看该类型的构件是否支持,得到正面的回答之后,再根据镜像匹配规则转而访问私服仓库地址。
4. 部署构件至 Nexus
如果只为代理外部公共仓库,那那么 Nexus 的代理仓库就已经能够完全满足需要了。对于另一类 Nexus 仓库一一宿主仓库来说,它们的主要作用是储存组织内部的,或者一些无法从公共仓库中获得的第三方构件,供大家下载使用。用用户可以配置 Maven 自动部署构件至 Nexus 的宿主仓库,也可以通过界面手动上传构件。
4.1 使用 Maven 部署构件至 Nexus
日常开发生成的快照版本构件可以直接部署到 Nexus 中策略为 Snapshot 的宿主仓库中,项目正式发布的构件则应该部署到到 Nexus 中策略为 Release 的宿主仓库中。POM 文件配置如下:
<project>
<distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Nexus Releases Repository</name>
<url>http://localhost:8081/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>Nexus Snapshots Repository</name>
<url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
Nexus 的仓库对于匿名用户是只读的。为了能够部署构件,还还需要在 settings.xml 中配置认证信息。
<settings>
<servers>
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
</settings>
4.2 手动部署第三方构件至 Nexus
某些 Java Jar 文件(如 Oracle)的 JDBC 驱动,由于许可证的因素,它们无法公开地放在公共仓库中。此外,还有大量的小型开源项目,它们没有把自己的构件分发到*仓库中,也没有维护自己的仓库,因此也无法从公共仓库获得。这个时候用户就需要将这类构件手动下载到本地,然后通过 Nexus 的界面上传到私服中。
要上传第三方构件,首先选择一个宿主仓库如 3rd party,然后在页面的下方选择 Artifact Upload 选项卡。在上传构件的时候, Nexus 要求用户确定其 Maven 坐标,如果该构件是通过 Maven 构建的,那么可以在 GAV Definition 下拉列表中选择 From POM,否则就选 GAV Parameters。用户需要为该构件定义一个 Maven 坐标,例如上传一个 Oracle 的 JDBC 驱动,则可以按图 16 所示输入坐标。
定义好坐标之后,单击 Select Artifact(s) to Upload 按扭从本机选择要上传的构件,然后单击 Add Artifact 按组件加入到上传列表中。Nexus 允许用户一次上传一个主构件和多个附属构件(即 Classifier)。最后,单击页面最下方的 Upload Artifact(s) 按钮将构件上传到仓库中。
更多参考 《Maven 实战》