先区分历史流程与当前入口
本文保留作者通过 OSSRH 发布构件的操作记录和截图。OSSRH 已于 2025 年 6 月 30 日关闭,命名空间迁移至 Central Publisher Portal;下文的 Jira 工单、旧仓库地址和 Nexus Staging 配置用于理解历史过程,不能照搬为当前发布教程。Sonatype 关闭与迁移说明
新项目在 Central Portal 验证命名空间、生成发布 token,再按 官方 Maven 发布指南 配置 central-publishing-maven-plugin。旧项目也可按官方文档使用兼容的 Staging API。发布插件不会自动补齐 sources、Javadoc、签名和必填 POM 元数据,构建时仍需生成并检查这些产物。上传、校验通过、正式发布和搜索可见是不同阶段。
历史记录:通过 OSSRH 发布
首先,先说一下大体的步骤:
- 注册Sonatype账号
- 创建Issue,验证域名
- 安装GPG,发布密钥
- 配置Maven,发布构件
这里面比较重要和容易出错的是第二步和第三步,下面一一详细介绍。
1、注册Sonatype账号
第一步很简单,登录官网,注册账号就好了Sign up for Jira - Sonatype JIRA
注册完成,登陆后的界面如下:

2、创建Issue
这里项目选择:Community Support - Open Source Project Repository Hosting (OSSRH),问题 类型选择:New Project

2.1、补充项目信息

2.2、验证域名
Group ID 通常以已经验证的域名反写命名空间开头。例如拥有 example.com,可以申请 com.example,再发布 com.example.myproject。对应关系例如:
- example.com -> com.example.domain
- www.springframework.org -> org.springframework
- subdomain.example.com -> com.example.subdomain
- github.com/yourusername -> io.github.yourusername
- my-domain.com -> com.my-domain
要想使用某个域名作为Group Id,你需要证明拥有该域名,至于如何证明,详见官方文档:https://central.sonatype.org/faq/how-to-set-txt-record/
如果你没有自己的域名,则可以通过代码托管平台的账号关联子域名。假设你托管平台账户名为myusername,那么你可以通过以下托管平台验证Group Id :

由于我没有自己的域名,这里我选择使用github账号验证Group Id。点击“新建”按钮,完成提交,之后你的注册邮箱会收到一封邮件,显示创建项目信息:

稍后还会收到一封审核邮件,提示你进行域名验证,时间延迟大概在十分钟以内。
2.3、人工审核及确认

我使用的是github账户,按邮件提示,需要在github平台上创建一个指定的临时工程。创建完成之后,可以在issue下面添加评论,触发验证。验证成功后,你会收到一份邮件:

收到上述邮件,就表示完成了Group Id的验证,此时你就可以使用该Group Id或者子Group Id发布Maven构件了。如上,我填写的Group Id是 “io.github.nianien”,因此,我可以使用 “io.github.nianien”或者 “io.github.nianien.xxx” 作为项目的GroupId发布Maven构件。
在通过Maven发布构件之前,我们需要进行Maven配置,这里还需要一些前置工作。
3、安装GPG,创建密钥
GPG 可以通过命令行或图形界面安装;能否发布公钥取决于密钥服务器和网络配置,与是否使用命令行没有必然关系。下面保留当时图形界面的操作记录。私钥留在受控环境,只发布公钥。
- 创建密钥

3.1、发布密钥

发布成功后,收到一份邮件:

按照邮件指示操作,完成密钥发布。密钥发布成功之后,下一步就是配置maven settings.xml和工程pom.xml文件。
4、配置Maven,发布构件
- 第一步,配置setting.xml文件,添加server节点:
<settings>
<servers>
<server>
<id>ossrh</id>
<username>${env.OSSRH_TOKEN_USERNAME}</username>
<password>${env.OSSRH_TOKEN_PASSWORD}</password>
</server>
</servers>
</settings>
以上保留历史服务器 ID;当前 Portal 使用其插件对应的服务器 ID 和 Portal token。GPG 口令通过 gpg-agent / pinentry 或构建环境的受控凭据机制提供,不写进项目 POM 或提交到 Git。
- 第二步,配置pom.xml文件,添加必填项
<?xml version="1.0" encoding="UTF-8"?>
<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><!--已经验证的Group Id-->
<groupId>io.github.nianien</groupId>
<artifactId>cudrania</artifactId>
<version>1.0.1</version><!--必填-->
<name>io.github.nianien:cudrania</name><!--必填-->
<description>support tools for java development</description><!--必填-->
<url>https://github.com/nianien/cudrania</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
</properties><!--必填-->
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses><!--必填-->
<developers>
<developer>
<id>nianien</id>
<name>nianien</name>
<email>nianien@126.com</email>
</developer>
</developers><!--必填-->
<scm>
<connection>scm:git:https://github.com/nianien/cudrania.git</connection>
<developerConnection>scm:git:ssh://git@github.com/nianien/cudrania.git
</developerConnection>
<url>https://github.com/nianien/cudrania</url>
</scm>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin><!--必填-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</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>3.5.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>
-Xdoclint:none
</additionalparam>
</configuration>
</execution>
</executions>
</plugin><!--必填-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles><!--必填-->
<profile>
<id>ossrh</id>
<build>
<plugins>
<plugin><!--必填-->
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin><!--必填-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
</plugin>
</plugins>
</build><!--必填-->
<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>
</profile>
</profiles>
<dependencies><!--maven依赖--></dependencies>
</project>
上面是当时使用的 POM 示例,包含项目坐标、许可证、开发者信息、源码地址,以及构建和发布插件。当前迁移时保留适用的项目元数据,并替换旧发布插件和地址。
需要说明的是,为了不用默认打包冲突,专门定义了用于发布中央仓库的profile:ossrh,这里只需要添加额外的两个插件:nexus-staging-maven-plugin和maven-gpg-plugin,前者用于jar上传,后者用于密钥签名。
- 第三步,执行maven命令,发布构件
配置好pom文件,可以执行maven命令:“mvn clean deploy -Possrh” 进行发布。如果版本号带SNAPSHOT后缀,会发布到snapshots仓库,否则发布到release仓库。
这里nexus-staging-maven-plugin插件有一个配置项:autoReleaseAfterClose,如果设置为true的话,推送完成会自动release。第一次发布成功后,会收到一封邮件:

- 最后,让jar包更快的在中央仓库被搜索到
根据邮件提示,Jar包成功发布成功后,大约30分钟后会推到中央仓库,我们可以从仓库地址看到我们发布的Jar包:https://repo1.maven.org/maven2/

此时,其他项目就可以通过maven依赖引用我们的构件了,但是这时候通过中央仓库仍然搜不到我们的Maven构件。按照邮件提示可能会需要四小时,实际情况是我等了5个小时依然搜不到。如果遇到这种情况,我们可以通过在对issue添加评论反馈,会有人工回复进行解决:

另外,关于mvnrepository与Maven Central的关系,有人咨询,官方也做了解答:

根据我的实际经验判断,mvnrepository应该是定时同步的,我发布成功后,第二天才能搜到:

下面是官方指导文档,介绍非常详细,基本上不用在网上搜索其他教程了。