如何发布 Java 包到 Maven 中央仓库

最近参与一些开源项目,涉及到发版相关的问题,没有看到详细又不过时的教程,于是自己调研摸索,总结出了这篇文章。

本文主要参考官方文档进行编写,演示仓库位于 https://github.com/seriouszyx/maven-release-example

准备工作

Coordinates

Maven 用 groupid 来标识项目空间,用域名逆序的方式命名。下面是两种命名的例子,如果有自己的域名,直接使用就可以;如果没有,可以使用 github 等代码托管服务的域名。

下面是支持个人 groupid 的代码托管服务,假设使用 io.github.myusername ,需要创建一个名为 OSSRH-TICKETNUMBER 的公开仓库进行验证(验证成功后可删除)。如果使用自己的域名,也需要添加 TXT 解析,稍后会提到。

服务 groupid 相关文档
GitHub io.github.myusername https://pages.github.com/
GitLab io.gitlab.myusername https://about.gitlab.com/stages-devops-lifecycle/pages/
Gitee io.gitee.myusername https://gitee.com/help/articles/4136
Bitbucket io.bitbucket.myusername https://support.atlassian.com/bitbucket-cloud/docs/publishing-a-website-on-bitbucket-cloud/
SourceForge io.sourceforge.myusername https://sourceforge.net/p/forge/documentation/Project%20Web%20Services/

artifactId 用来标识项目本身,如果项目命名很长,可以使用“-”来进行分隔。

GPG

将组件发布到 Maven 中央仓库需要使用 PGP 进行签名,GnuPG (又称 GPG) 都是 OpenPGP 的实现,需要先创建你自己的键值对,再上传到服务器以供验证。

https//www.gnupg.org/download/ 下载安装,使用 --version 标志检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ gpg --version
gpg (GnuPG) 2.2.28
libgcrypt 1.8.8
Copyright (C) 2021 g10 Code GmbH
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: C:/Users/Yixiang Zhao/AppData/Roaming/gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

安装成功后产生键值对,过程中需要填写姓名、邮箱和密码,密钥有效期为 2 年,到时候需要使用密码延长有效期,可以看到我的公钥 id 是 444D548E4E29746B4E2C89FC89985FBD3651A87B

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ gpg --gen-key
gpg (GnuPG) 2.2.28; Copyright (C) 2021 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name: Yixiang Zhao
Email address: seriouszyx@gmail.com
You selected this USER-ID:
"Yixiang Zhao <seriouszyx@gmail.com>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 89985FBD3651A87B marked as ultimately trusted
gpg: directory 'C:/Users/Yixiang Zhao/AppData/Roaming/gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as 'C:/Users/Yixiang Zhao/AppData/Roaming/gnupg/openpgp-revocs.d\444D548E4E29746B4E2C89FC89985FBD3651A87B.rev'
public and secret key created and signed.

pub rsa3072 2021-10-14 [SC] [expires: 2023-10-14]
444D548E4E29746B4E2C89FC89985FBD3651A87B
uid Yixiang Zhao <seriouszyx@gmail.com>
sub rsa3072 2021-10-14 [E] [expires: 2023-10-14]

后续步骤需要通过你的公钥来进行验证,所以把它上传到服务器中,注意 --send-keys 后面是你自己的公钥。

1
2
$ gpg --keyserver keyserver.ubuntu.com --send-keys 444D548E4E29746B4E2C89FC89985FBD3651A87B
gpg: sending key 89985FBD3651A87B to hkp://keyserver.ubuntu.com

等大概十几分钟,验证公钥是否发布成功。

1
2
3
4
$ gpg --keyserver keyserver.ubuntu.com --recv-keys 444D548E4E29746B4E2C89FC89985FBD3651A87B
gpg: key 89985FBD3651A87B: "Yixiang Zhao <seriouszyx@gmail.com>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1

在 Sonatype 创建 Issue

开发者要想将组件发布至 Maven 中央仓库,需要借助于 Sonatype 的开源软件存储库托管(Open Source Software Repository Hosting, OSSRH)服务。Sonatype 使用 JIRA 来管理请求,所以需要先注册账号

注册好之后,就可以创建一个新的 Issue(文档中又称 Project ticket),可以参考我创建的测试 Issue OSSRH-74121

这时需要进行人工审核,将分配的编号 OSSRH-74121 添加到域名的 TXT 解析,或者在 GitHub 等托管服务中创建一个名为 OSSRH-74121 的公开库。我等了大概一两个小时,就通过了审核,Status 变成了 RESOLVED

配置发布信息

本文使用 Maven 为例发布自己的 Java 包,如果使用 Gradle、Ant 等工具,可以参照官方文档。

分发管理和认证

pom.xml 中添加以下配置,使得可以使用 Nexus Staging Maven plugin 插件向 OSSRH Nexus Repository Manager 发布。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
...
</plugins>
</build>

下面是发布所需的 JIRA 账户信息,写入到 Maven 的 setting.xml 文件中(通常位于 ~/.m2)。

1
2
3
4
5
6
7
8
9
<settings>
<servers>
<server>
<id>ossrh</id>
<username>your-jira-id</username>
<password>your-jira-pwd</password>
</server>
</servers>
</settings>

注意这里的 id 和 snapshotRepository /repository 中的 id,以及 plugin 中的 id 都是相同的,都为 ossrh

Javadoc 和源代码

为了生成 Javadoc 和源 jar 文件,需要在 pom.xml 中添加以下配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

GPG 签名组件

Maven GPG 插件使用以下配置为组件进行签名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

并在 setting.xml 中配置 gpg 的运行文件和密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<settings>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>D:/Work/GnuPG/bin/gpg.exe</gpg.executable>
<gpg.passphrase>the_pass_phrase</gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>

如果想要发布正式版本,还需要在 pom.xml 中配置项目名、描述、开发者等信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<name>maven-release-example</name>
<description>Example project to deploy maven projects.</description>
<url>https://github.com/seriouszyx/maven-release-example</url>
<licenses>
<license>
<name>MIT</name>
<url>https://opensource.org/licenses/MIT</url>
</license>
</licenses>
<developers>
<developer>
<name>Yixiang Zhao</name>
<email>seriouszyx@gmail.com</email>
<organization>seriouszyx</organization>
<organizationUrl>https://seriouszyx.com/</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/seriouszyx/maven-release-example.git</connection>
<developerConnection>scm:git:https://github.com/seriouszyx/maven-release-example.git</developerConnection>
<url>https://github.com/seriouszyx/maven-release-example</url>
</scm>

发布

更改 pom.xml 中的版本号为 1.0.0 , 在项目根目录运行 mvn clean deploy 即可发布,发布成功后组件会存储到一个临时存储库中,只对团队成员开放,可以在 https://s01.oss.sonatype.org/ 访问,点击右上角登录 JIRA 的账号,搜索刚发布的组件,即可查询到相关信息。

因为之前在 maven 插件 nexus-staging-maven-plugin 中的 autoReleaseAfterClose 属性设置为 true 了,所以自动上传到 staging repository ,并且自动执行了 close->release->drop 三步曲,等待两小时后就可以在 https://search.maven.org 查到了。

在新建工程的 pom.xml 种添加依赖,即可使用 jar 包中的方法。

1
2
3
4
5
<dependency>
<groupId>com.seriouszyx</groupId>
<artifactId>maven-release-example</artifactId>
<version>1.0.0</version>
</dependency>

  1. The Central Repository Documentation
  2. 发布项目到中央库的一些常见问题