掘金 后端 ( ) • 2024-04-21 10:53

1. 概述

在2024年1月9号之前,如果想要发布 JAR 包到 Maven 仓库需要在 issues.sonatype.org 上提交 issue(工单)。但在1月9号,central.sonatype.org 官网发布声明,它们将很快停用 issues.sonatype.org,后续可以通过 central.sonatype.com 发布 JAR 包。

2. 提前的准备

  • 本机配置 Git 环境并注册 GitHub 或者 Gitee 账号
  • 本机配置 Java 开发环境,包括安装 JDK 1.8(本文使用的版本)、IDEA(哪个版本都行,推荐使用社区版)
  • 本机配置 Maven 环境
  • 本机配置 Node 和 Vue 环境

3. 操作流程

3.1. 注册账号

central.sonatype.com 网站支持通过邮箱注册账号、使用 GitHub 或者 Google 账号登录。如果访问 GitHub 的网速还可以,推荐使用 GitHub 账号登录该网站,它会自动注册一个命名空间,命名空间的格式为io.github.<username>,例如,如果你的 GitHub 的账号名称为 example,那么命名空间的名称为 io.github.example。如果不想用 github 格式的命名空间,可以登录后再创建新的命名空间即可。

3.2. 创建并验证命名空间

如果你使用 GitHub 登录的,该步骤可跳过。

在发布一个组价(也就是 JAR 包)之前,必须选择一个命名空间。在 Maven 生态系统中,命名空间也可称为 groupid,它和 artifactid、version 一同用来描述将组件发布到 Maven Central 所需的三个坐标。命名空间在 Maven Central 中用来唯一标识你的顶级项目或者你的组织。

在 Sonatype 验证你在你请求的命名空间下发布的权限之前,需要验证你是否拥有该命名空间对应的 Web 域的管理权限。通常有两种方式支持这种验证:通过 DNS 或者通过代码托管服务。本文只介绍后者的验证方式,前一种的验证方式可以查看官网的描述即可。

通过代码托管服务的方式来验证命名空间,需要你创建一个临时的公共仓库,该仓库的名称需要按照 Sonatype 分配的值设置。

示例:使用 GitHub 演示代码托管服务的验证方式

  1. 创建一个新的命名空间,其中,example 表示一个 GitHub 用户名

  1. 点击 Verify Namespce 按钮,获取该命名空间对应的验证密钥

  1. 在 example 账户下创建域验证密钥同名的公共仓库,然后点击上图中的 Confirm 按钮即可。

3.3. 创建 GPG 公钥和私钥

在将 JAR 包发布到 Maven Central 仓库之前,需要确保它们已使用 PGP 签名,其中,GenuPG 和 GPG 都是 OpenPGP 标准的免费实现。GPG 提供生成签名、管理密钥和验证签名的功能,大体步骤包括如下两步:

  • 创建属于你自己的公钥、私钥
  • 将公钥发布到一个密钥服务器上,让其他用户可以验证这个 JAR 包

3.3.1. 下载并安装 GnuPG

根据你的操作系统 下载 GnuPG 后,使用默认方式安装即可,安装成功后使用gpg --version验证。

3.3.2. 创建密钥对

GnuPG 安装成功后,可以使用命令行或者 Kleopatra 软件创建密钥对。密钥对能够让你使用 GPG 签署 JAR 包,并且其他用户随后可以使用公钥验证这个 JAR 包是否由你签名。

创建密钥对的命令为gpg --gen-key,然后根据提示输入用户名和邮件,然后在弹出的窗口设置一个密码,用来保护密钥对。创建的密钥对默认有效期为3年,后续可以使用其他命令,将有效期设置为永不失效。

3.3.3. 分发公钥

由于其他使用你的 JAR 的用户需要使用公钥来验证 JAR 包,因此你需要将公钥分发到一个密钥服务器上,具体命令如下:

gpg --keyserver keyserver.ubuntu.com --send-keys <你的公钥>

其中,--keyserver用来表示一个密钥服务器、--send-keys标识要分发的密钥。Maven Central 支持的 GPG 密钥服务器列表如下:

  • keyserver.ubunut.com
  • keys.openpgp.org
  • pgp.mit.edu

分发后,也可以使用如下命令确认公钥是否可以正常的被获取到。

gpg --keyserver keyserver.ubuntu.com --recv-keys <公钥>

3.3.4. 其他命令

3.3.4.1. 查看所有密钥对

可以使用命令gpg --list-keys查看本机所有的密钥对。

$ gpg --list-keys
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub   rsa3072 2021-06-23 [SC] [expires: 2023-06-23]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid           [ultimate] Central Repo Test <[email protected]>
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]

3.3.4.2. 修改密钥对的过期时间

可以使用如下命令编辑指定密钥对的过期时间

  1. 使用gpg --list-keys获取需要更改的密钥对的公钥
  2. 使用gpg --edit-key <公钥>命令修改密钥对
$ gpg --edit-key CA925CD6C9E8D064FF05B4728190C4130ABA0F98
gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2023-06-23  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
[ultimate] (1). Central Repo Test <[email protected]>

gpg>
  1. 根据提示键入1,然后就可以看到(1)后面的点改为星号,表示当前你已经选中它。
gpg> 1

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2023-06-23  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
[ultimate] (1)* Central Repo Test <[email protected]>
  1. 键入 expire 然后回车,根据提示修改密钥的过期时间,如果想取消过期时间,可以键入0,然后在弹出的窗口中输入之间设置的密码
gpg> expire
Changing expiration time for the primary key.
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 
  1. 键入 save,保存更改
gpg> save

3.3.4.3. 删除密钥对

重复上面的1、2、3步,然后键入 delkey,然后键入 save,保存更改。如果你已经分发了公钥,最好撤销而不是删除它,撤销的命令为 revkey。

3.4. 生成用户Token

新的发布方式不允许在 Maven 中直接配置 Sonatype 的用户名和密码,而是需要一个用户 Token,具体操作如下:

  1. 访问并登录 central.sonatype.org 网站
  2. 点击右上角的用户名,选择 View Account
  3. 点击 Generate User Token,然后保存用户名和密码。

需要注意,这里生成的用户名和密码只能使用一次,也就说,下次在更新 JAR 包之前,需要按照相同的方式重新生成用户名和密码。

3.5. 配置Maven的setting.xml

编辑 setting.xml 文件,主要修改 servers 和 profiles 标签。

servers 标签

  <servers>
    <server>
      <!-- id 是固定的 -->
      <id>central</id>
      <!-- 每次部署之前需要申请一个新的用户名和密码,配置好了直接点击 Maven 中的 deploy 即可 -->
      <username>token-username</username>
      <password>token-password</password>
    </server>
  </servers>

profiles 标签

<profiles>
    <profile>
      <id>central</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <!-- gpg.exe 文件的位置 -->
        <gpg.executable>C:\Program Files (x86)\GnuPG\bin\gpg</gpg.executable>
        <!-- 创建密钥对时配置的密码 -->
        <gpg.passphrase>密码</gpg.passphrase>
      </properties>
    </profile>
</profiles>

3.6. 创建并部署Maven项目

使用 IDEA 创建并发布 Maven 项目,具体部署如下:

  1. 使用 IDEA 创建一个空的 Maven 项目,本文使用是 IDEA 社区版,具体配置选项如下,需要注意,版本编号中不能包含 SNAPSHOT。

  1. 编辑 pom.xml 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>io.gitee.example</groupId>
  <artifactId>example</artifactId>
  <!-- 新版本不支持version中包含SNAPSHOT,而是直接发布到中央仓库 -->
  <version>0.0.1</version>
  <packaging>jar</packaging>

  <name>gis-tools</name>
  <!-- description必须有,否则上传时提示错误 -->
  <description>描述信息</description>
  <url>可以是仓库地址</url>

  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
    </license>
  </licenses>

  <developers>
    <developer>
      <name>jiaoxn</name>
      <email>邮件</email>
      <!-- organization及相关信息,可选 -->
      <organization>组织名称</organization>
      <organizationUrl>组织官网</organizationUrl>
      <url>可以是仓库地址</url>
      <timezone>+8</timezone>
    </developer>
  </developers>

  <scm>
    <!-- 项目URL -->
    <url>仓库地址,不带.git</url>
    <!-- 项目URL.git -->
    <connection>scm:git:仓库地址.git</connection>
    <!-- 项目URL.git -->
    <developerConnection>scm:git:仓库地址.git</developerConnection>
  </scm>

  <properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 服务id 也就是setting.xml中的servers.server.id -->
    <serverId>central</serverId>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- 编译插件,设置源码以及编译的jdk版本 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>${maven.compiler.source}</source>
          <target>${maven.compiler.target}</target>
        </configuration>
      </plugin>
      <!-- Source -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>2.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>jar-no-fork</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- Javadoc -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>2.9.1</version>
        <configuration>
          <additionalparam>-Xdoclint:none</additionalparam>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- Javadoc -->
      <!-- Gpg Signature -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-gpg-plugin</artifactId>
        <version>1.6</version>
        <executions>
          <execution>
            <phase>verify</phase>
            <goals>
              <goal>sign</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- 新方式的配置,将组件部署到OSSRH并将其发布到Central Repository-->
      <plugin>
        <groupId>org.sonatype.central</groupId>
        <artifactId>central-publishing-maven-plugin</artifactId>
        <version>0.4.0</version>
        <extensions>true</extensions>
        <configuration>
          <publishingServerId>central</publishingServerId>
          <tokenAuth>true</tokenAuth>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <distributionManagement>
    <snapshotRepository>
      <id>${serverId}</id>
      <url>https://central.sonatype.com/</url>
    </snapshotRepository>
  </distributionManagement>
</project>
  1. 发布

在 IDEA 中可以选择右侧 Maven 列表中声明周期的 deploy 按钮,将 Maven 项目打包并发布到 Sonatype。对应的 Maven 命令为mvn deploy -e,其中,-e参数可以打印 deploy 过程中的错误信息,以便排查问题。

3.7. 发布JAR包

在执行 Maven 的 deploy 后,JAR 包并不会直接发布到 Maven Central 仓库中,而是在 Sonatype 中处于 VALIDATED 状态,需要登录 central.sonatype.com 网站,手动点击发布,具体操作如下:

  1. 登录 central.sonatype.com 网站,并打开命名空间
  2. 切换到 Deployment 面板,找到对应处于 VALIDATED 状态的 JAR 包,点击 Publish 按钮执行发布,整个发布过程大概会持续30分钟左右

3.8. 验证 JAR 包是否发布成功

访问 central.sonatype.com 网站,在搜索框中输入命名空间(例如:io.gitee.example),可以验证 JAR 包是否发布成功。

4. 参考文章