手把手带你发布一个JAR包到Maven仓库

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 包,因此你需要将公钥分发到一个密钥服务器上,具体命令如下:

css 复制代码
gpg --keyserver keyserver.ubuntu.com --send-keys <你的公钥>

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

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

css 复制代码
gpg --keyserver keyserver.ubuntu.com --recv-keys <公钥>

3.3.4. 其他命令

3.3.4.1. 查看所有密钥对

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

css 复制代码
$ gpg --list-keys
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub   rsa3072 2021-06-23 [SC] [expires: 2023-06-23]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid           [ultimate] Central Repo Test <central@example.com>
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]

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

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

  1. 使用gpg --list-keys获取需要更改的密钥对的公钥
  2. 使用gpg --edit-key <公钥>命令修改密钥对
vbnet 复制代码
$ 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 <central@example.com>

gpg>
  1. 根据提示键入1,然后就可以看到(1)后面的点改为星号,表示当前你已经选中它。
yaml 复制代码
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 <central@example.com>
  1. 键入 expire 然后回车,根据提示修改密钥的过期时间,如果想取消过期时间,可以键入0,然后在弹出的窗口中输入之间设置的密码
vbnet 复制代码
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,保存更改
shell 复制代码
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 标签

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

profiles 标签

xml 复制代码
<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 文件
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. 参考文章

相关推荐
小坏讲微服务29 分钟前
SpringCloud零基础学全栈,实战企业级项目完整使用
后端·spring·spring cloud
humors2211 小时前
服务端开发案例(不定期更新)
java·数据库·后端·mysql·mybatis·excel
Easonmax3 小时前
用 Rust 打造可复现的 ASCII 艺术渲染器:从像素到字符的完整工程实践
开发语言·后端·rust
百锦再3 小时前
选择Rust的理由:从内存管理到抛弃抽象
android·java·开发语言·后端·python·rust·go
小羊失眠啦.3 小时前
深入解析Rust的所有权系统:告别空指针和数据竞争
开发语言·后端·rust
q***71854 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
大象席地抽烟4 小时前
使用 Ollama 本地模型与 Spring AI Alibaba
后端
程序员小假4 小时前
SQL 语句左连接右连接内连接如何使用,区别是什么?
java·后端
小坏讲微服务4 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway
方圆想当图灵5 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(下)
分布式·后端·github