序言
最近收到Sonatype的迁移提醒邮件,内容大意为:原有的OSSRH发布模式将在2025年6月30日停止维护,之后原有的OSSRH发布方式将不再适用,需要尽快迁移到Maven Central。如果你之前使用过OSSRH但是没有使用过Maven Central发布Jar包、或者想要从0开始学习如何将Jar包发布到中央仓库,都可以通过本文章学习。本文章将会从0开始,一步一步引导你如何将Jar包发布到Maven Central中央仓库。
![]()
文章目录
- Maven仓库账号准备
- GPG密钥工具准备
- 部署流程
1. Maven仓库账号准备
Tips:之前在OSSRH上发布过Jar/War包的,可以使用已有的账号,迁移更方便
1.1. Sonatype账号注册和登录
打开 Maven Contral ,找到右上角的「Sign in」进行注册或登录
1.2. 创建/迁移命名空间
登录之后,还是右上角,找到「View Namespaces」
按照图中的步骤说明,创建或者迁移命名空间
1.3. 校验命名空间(迁移已有的命名空间不需要该步骤)
注意:如果你的命名空间是一个域名,则需要做「DNS TXT Record」DNS文本记录校验
1.4. 生成用户访问令牌
还是右上角,找到「View Account」,点击之后会进到一个很简洁的账号管理界面,需要在这个页面生成后续流程所需的用户访问令牌
保存好你的令牌,不要泄露出去,如果重新生成了令牌,原有的令牌过一段时间之后将会失效。
1.5. 配置用户访问令牌到Maven环境
将用户访问令牌配置到Maven的
settings.xml配置文件中。此处以IDEA为例,请按照你实际具体使用的Maven环境进行配置。
2. GPG密钥工具准备
2.1 GPG密钥工具下载安装
打开 GunPG Download ,找到 「GnuPG binary releases」项,根据电脑的环境下载安装合适的GPG工具。下面以Windwos 10/11为例。
Tips:开源不易,有能力可以适当支持一下GPG的开源工作
软件支持中文,安装目录随意,步骤选项默认即可。
2.2 密钥生成和上传公钥服务器
GPG4Win支持GUI图形界面和命令行生成密钥
Maven中央服务器支持的 GPG 密钥服务器有好几个,如遇报错或者网络问题,可以切换尝试以下服务器:
keyserver.ubuntu.com
keys.openpgp.org
pgp.mit.edu
2.2.1 图形界面生成密钥
打开Kleopatra密钥管理工具(即GPG的GUI客户端)
2.2.2 命令行生成密钥
打开终端工具输入
gpg --version如果没有输出版本信息说明环境不对,检查一下安装。
下图中用到的命令
输出GPG版本环境信息:
gpg --version生成密钥:
gpg --gen-key下图中用到的命令
查看秘钥:
gpg --list-keys上传密钥到公钥服务器:
gpg --keyserver keyserver.ubuntu.com --send-keys 密钥pub指纹验证是否成功上传到公钥服务器:
gpg --keyserver keyserver.ubuntu.com --recv-keys 密钥pub指纹
2.3 配置GPG密钥到Maven环境
将GPG密钥配置到Maven的
settings.xml配置文件中。具体配置文件可以查看上文中的1.5. 配置用户访问令牌到Maven环境步骤
3. 部署流程
部署不成功的,可以参考一下下面的配置。
在阅读下面的配置之前,需要注意的如下几点:
项目的
groupId必须和Maven Central的命名空间一致
pom.xml中必须包括:name、description、url、licenses、developers、scm等基本信息标签,在执行deploy的时候,需要使用 Maven 配置环境中的 GPG 密钥profile(即上面我们配的gpg密钥)对源码包、文档包、字节码包进行 GPG 数字签名。多模块项目只需要在父工程的
pom.xml中声明这些,子模块pom.xml中只需要修改相应的一些信息即可,如name标签。
central-publishing-maven-plugin插件中的publishingServerId需要与Maven配置环境文件settings.xml中的server的id保持一致(即步骤1.5. 配置用户访问令牌到Maven环境中我们配置的server)
3.1 项目pom.xml配置
以下
pom.xml,有五个插件是必须的,分别是:
maven-compiler-plugin插件用于编译字节码包maven-source-plugin插件用于构建源码包maven-javadoc-plugin插件用于构建文档包maven-gpg-plugin插件用于打包GPG数字签名central-publishing-maven-plugin插件用于推送包到Maven Central下面以我成功发布的项目单模块项目 netty-socketio-spring-boot-starter 为例,多模块可参考我另一个成功发布的项目 mapstruct-convert 。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- parent表示依赖父工程,这个不是必须的,如果你的项目没有依赖任何父工程,这个可以删掉 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 下面的一些基本的标签,必须要有 -->
<groupId>io.github.deersunny</groupId>
<artifactId>netty-socketio-spring-boot-starter</artifactId>
<version>2.0.0</version>
<name>netty-socketio-spring-boot-starter</name>
<description>The project is NettySocketIO Spring Boot Starter</description>
<url>https://github.com/ColorDreams/${project.artifactId}</url>
<packaging>jar</packaging>
<!-- 协议信息标签,必须要有 -->
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<!-- 开发人员信息,必须要有,改成你自己的,developer 可以配置多个 -->
<developers>
<developer>
<name>ColorDreams</name>
<email>505073804@qq.com</email>
<timezone>+8</timezone>
</developer>
</developers>
<!-- 仓库信息,必须要有,改成你自己的 -->
<scm>
<url>https://github.com/ColorDreams/${project.artifactId}</url>
</scm>
<!-- issue管理配置,改成你自己的 -->
<!-- 可以使用 <issueManagement/> 闭合标签,表示忽略该项配置,该标签必须要有,不能删除 -->
<issueManagement>
<system>GitHub</system>
<url>https://github.com/ColorDreams/${project.artifactId}/issues</url>
</issueManagement>
<properties>
<!-- project java version -->
<java.version>17</java.version>
<!-- project encoding -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- project dependency package version -->
<spring-boot.version>3.4.5</spring-boot.version>
<netty-socketio.version>2.0.13</netty-socketio.version>
<!-- project dependency plugin version -->
<apache-maven-plugins.groupId>org.apache.maven.plugins</apache-maven-plugins.groupId>
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
<maven-source-plugin.version>3.3.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.11.2</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>3.2.7</maven-gpg-plugin.version>
<license-maven-plugin.version>5.0.0</license-maven-plugin.version>
<central-publishing-maven-plugin.version>0.7.0</central-publishing-maven-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring-hooks-dependencies dependency -->
<!-- https://central.sonatype.com/artifact/org.springframework.boot/spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- netty-socketio dependency -->
<!-- https://central.sonatype.com/artifact/com.corundumstudio.socketio/netty-socketio -->
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>${netty-socketio.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- 编译插件,插件是必须的 -->
<!-- compiler plugin -->
<!-- https://central.sonatype.com/artifact/org.apache.maven.plugins/maven-compiler-plugin -->
<plugin>
<groupId>${apache-maven-plugins.groupId}</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- jar源码包生成插件,插件是必须的 -->
<!-- build source package plugin -->
<!-- https://central.sonatype.com/artifact/org.apache.maven.plugins/maven-source-plugin -->
<plugin>
<groupId>${apache-maven-plugins.groupId}</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<configuration>
<!-- 源码包随着项目打成的jar包安装到本地仓库或者私服、公服 -->
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- javadoc生成插件,插件是必须的 -->
<!-- gen javadoc plugin -->
<!-- https://central.sonatype.com/artifact/org.apache.maven.plugins/maven-javadoc-plugin -->
<plugin>
<groupId>${apache-maven-plugins.groupId}</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 禁用严格语法检测 -->
<doclint>none</doclint>
</configuration>
</plugin>
<!-- GPG签名插件,插件是必须的 -->
<!-- gpg sign plugin -->
<!-- https://central.sonatype.com/artifact/org.apache.maven.plugins/maven-gpg-plugin -->
<plugin>
<groupId>${apache-maven-plugins.groupId}</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 发布到maven仓库中心插件,插件是必须的 -->
<!-- publishing to central server plugin -->
<!-- https://central.sonatype.com/artifact/org.sonatype.central/central-publishing-maven-plugin -->
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central-publishing-maven-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<!-- 注意:这类必须要和Maven配置环境中的server id对应上 -->
<publishingServerId>central</publishingServerId>
</configuration>
</plugin>
<!-- 开源协议管理插件,用于给源码生成开源协议信息头,插件不是必须的,可以删掉 -->
<!-- gen code license plugin -->
<!-- https://central.sonatype.com/artifact/com.mycila/license-maven-plugin -->
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>${license-maven-plugin.version}</version>
<configuration>
<basedir>${basedir}</basedir>
<quiet>false</quiet>
<failIfMissing>true</failIfMissing>
<aggregate>false</aggregate>
<useDefaultExcludes>true</useDefaultExcludes>
<useDefaultMapping>true</useDefaultMapping>
<mapping>
<java>SLASHSTAR_STYLE</java>
</mapping>
<strictCheck>true</strictCheck>
<failIfMissing>true</failIfMissing>
<aggregate>true</aggregate>
<strictCheck>true</strictCheck>
<encoding>${project.build.sourceEncoding}</encoding>
<licenseSets>
<licenseSet>
<header>${basedir}/LICENSE-2.0.txt</header>
<!-- <header>com/mycila/maven/plugin/license/templates/APACHE-2.txt</header>-->
<excludes>
<exclude>**/README</exclude>
<exclude>src/test/resources/**</exclude>
<exclude>src/main/resources/**</exclude>
<exclude>**/generated/**</exclude>
<exclude>target/**</exclude>
</excludes>
<includes>
<include>src/main/java/**/*.java</include>
</includes>
</licenseSet>
</licenseSets>
<properties>
<owner>秋辞未寒</owner>
<email>545073804@qq.com</email>
<year>2025</year>
</properties>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- 依赖下载加速镜像,可以不用配 -->
<repositories>
<repository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!-- 插件依赖下载加速镜像,可以不用配 -->
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>huawei nexus</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<!-- 部署管理配置,基本不需要修改,原来是必须要配的 -->
<!-- 新的发布方式已经不需要该配置了,可以删掉 -->
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<name>OSS Snapshots Repositories</name>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<name>OSS Staging Repositories</name>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</project>
3.2 部署
使用
lifecycle中的deploy指令即可实现一键打包部署
3.3 注意事项
使用IDEA打包时,需要使用
lifecycle中的命令项,禁止使用plugins中的插件
发布快照包需要到Maven Central命名空间管理界面,启用 Snapshots 模式