发布/上传Jar包到Maven中央仓库 - 史上最详细

发布 Jar 包到 Maven 中央仓库

在项目开发过程中,我们常常会使用 Maven / Gradle 从仓库拉取开源的第三方 jar 包,可能是私有仓库,可能是 Maven 中央仓库,也可能是第三方的镜像。本文将一些简单实用的操作步骤和示例,带领大家将自己写好的代码或开源项目发布到 Maven中央仓库(https://mvnrepository.com/)中,让其他人可以直接依赖你的 jar 包,而不需要先下载你的代码 / jar 后 install 到本地。。

Maven中央仓库并不支持直接发布 jar 包,需要将 jar 包发布到一些指定的第三方Maven仓库,然后该仓库再将 jar 包同步到 Maven中央仓库,Sonatype便是 Maven中央仓库指定的暂存库。

准备工作

  • 本教程以 Maven 项目为例,作者使用的开发环境为:win10 + jdk8 + maven 3.6.3 。请提前准备好能成功打包的项目。
  • Sonatype 的相关地址在国外,如遇网络问题可以换时间段尝试或者自行准备 vpn 、代理等其他方式。
  • 网站存在部分英文,如阅读 / 沟通困难,可以使用 Chrome 浏览器的页面翻译插件,或者使用其他翻译工具进行辅助。
  • Sonatype 使用 JIRA工单系统来管理 OSSRH 仓库,对 JIRA 不了解的童鞋可以度娘查询相关的操作及页面释义。
  • 此过程由于需要国外管理员审核,使用 JIRA 工单评论进行交流,可能每次审核答复时间从几分钟到几小时不等,大家在此过程中可以时不时刷新页面或者留意邮件通知。

Sonatype 帐号

Sonatype 地址: https://issues.sonatype.org/secure/Dashboard.jspa

如果未使用过 Sonatype 系统,需要先注册一个帐号。

  • Email: 填写自己的邮箱帐号即可,在 Sonatype 上的相关操作,会通知到这个邮箱帐号来提醒你相关进度。
  • Full name: 填写联系人名称。
  • Username: 这个就是你在 Sonatype 的登录帐号了。
  • Password: 为登录密码,要求至少8位,并带有大小写字母和字符。

Sign up

注册完帐号首次登录时,会让你选择界面语言,按个人喜好选择即可(PS: 选择中文时部分操作按钮和说明会是中文,但界面和沟通语言仍为英语)。

项目申请

创建工单

可以理解为在 Sonatype 系统中申请一个自己的项目,以 Group Id 为单位,Group Id 支持域名地址Github 地址两种方式验证,大家可根据实际情况自行选择。申请后需要经过管理员对我们填写的 Group Id 所有权进行验证,审核通过后方可上传 jar 包。我们在页面顶部点击 Create 按钮来创建工单。

  • Project: 项目类型。选择 Community Support - Open Source Project Repository Hosting (OSSRH)
  • Issue Type: 工单类型。选择 New Project
  • Summary: 填写 jar 包名称即可
  • Description: 选填项,写一些描述
  • Group Id: 填写项目的Group Id,域名和 Github Group Id两种方式下面分别介绍申请过程
  • Project URL: 填写项目主页,可以是托管地址,也可以是官网地址
  • SCM URL: 填写项目的 Git 地址
域名 Group Id

如果有自己的域名(拥有域名所有权),则可以使用域名作为 Group Id。命名规则是域名的反向名称,比如我的域名是 wxdfun.com,那么我的 Group Id 可以使用 com.wxdfun 或者 com.wxdfun.** 。如果你的项目是多模块项目,则建议你在 Group Id 后面附加一个新的标识符,比如 com.wxdfun.plugins ,表示该 Group Id 下的项目为插件模块。下图为使用域名作为 Group Id 创建工单示例。

Group Id By Domain

Github Group Id

如果你还没有一个属于自己的域名,那我们可以直接使用 Github 的地址作为 Group Id 。Github Group Id 采用com.github.username 的命名方式,比如我在 Github 的帐号地址为 https://github.com/wxdfun ,那我的 Group Id 即为 com.github.wxdfun。下图为使用 Github Group Id 创建工单示例。

Group Id By Hosting

资质审核

创建完工单后,会显示一个未解决的工单(Resolution: Unresolved,Status: OPEN),同时在页面可以看到 JIRA 分配了一个管理员来跟进此工单作业。运气好过两分钟就会有人回复你相关的审核信息了,最长不超过1天应该,毕竟国内外存在时间差,工作人员也是需要下班休息的。

Unresolved Issue

请耐心等候即可,若未及时回复,可以挂起页面去干些别的事情。下面分别是域名 Group IdGithub Group Id 的审核过程示例。

域名 Group Id

使用域名申请的,一般会得到类似下图的回复(此图是我申请之后截图的,图中标红部分由于我验证通过变成了我的工单号,原本应该是一个 TXT 验证的字符串地址)。他的意思是询问我们填的 Group Id 那个域名是不是自己的,支持两种验证方式:

  • 域名 TXT 记录验证。需要在域名的 DNS 解析中添加一条 TXT 解析记录,目标值为上图红圈部分(新工单收到的回复应该是一个长字符串),官方说此方式最快。
  • Github 重定向验证。需要设置你的域名重定向到申请所填的 Github URL 地址。

Domain Group Id Comment.1

作者使用域名 TXT 记录验证的方式,我的域名是在阿里云买的,所以我在阿里云域名解析控制台添加 TXT 解析记录。其他服务商的域名解析请自行查询操作方式。

Domain Group Id DNS TXT

如果想要验证记录是否生效,可使用 nslookup -q=txt OSSRH-65507.wxdfun.com 命令进行验证。

nslookup txt

解析生效后,需要我们在页面对工单进行评论,告诉管理员我们已经将域名解析到对应地址。之后就等待管理员审核。

Domain Group Id Comment.2

Github Group Id

使用 Github Group Id 申请的,则会收到类似下图的回复,他告诉我们需要在自己的 Github 仓库中新建一个名为工单号的项目。

Github Group Id Comment.1

作者这里项目名是 OSSRH-65608 ,并且该项目需要是 public 的权限,即所有人可访问,接下来在 Github 创建一个空项目。

Create Github Repository

创建完 Github 项目后,我们需要在页面上评论工单,告诉管理员我们已经创建好了他指定的项目。之后等待管理员审核。

Github Group Id Comment.2

审核通过

若收到类似下图的回复,则证明我们的项目审核通过了,而且工单的状态变更为[Resolution: RESOLVED,Status: Fixed],说明我们已经可以发布我们的 jar 包到中央仓库了,另外回复中告知我们如果第一次发布 jar 包,需要在工单中评论。

Issue Resolved

以前回复的地址域名为 oss.sonatype.org ,官方已声明建议使用新域名地址 s01.oss.sonatype.org。

而且之前的回复中会带上 snapshot 快照版和release 正式版的仓库地址,但新版回复中仅告诉我们在 https://s01.oss.sonatype.org/ 上进行配置。我们打开他回复中提供的开发文档 https: //central.sonatype.org/pages/ossrh-guide.html#deployment 可以找到新的 snapshot 快照版和release 正式版的仓库地址。这个地址在下面进行的配置中会用到。

ossrh-guide usage notes

GPG签名

GPG 的主要作用是生成密钥对,发布到 Maven 仓库中的所有文件都要使用 GPG 签名,以保障完整性。使用 Windows 的可以下载gpg4win 地址:https://www.gpg4win.org/download.html ,安装后执行 gpg --gen-key 命令新建密钥对。

执行命令后,需要输入 姓名 和 邮箱 还有 Passphase(证书密码),Passphase 需要记住,在我们使用证书的时候会要求我们输入密码。

gpg

执行完之后我们会得到上图中的 pub 串,接着我们执行以下命令将 pub 上传到 key 验证库(后面的串替换为自己的)。

gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys
E89F2504BF0CE3337B26E45E485D1495DA08F9F6 

Maven 配置

setting.xml

首先是 Maven 全局配置文件 setting.xml,路径为 $MAVEN_HOME/conf/settings.xml ,若不知道该配置文件在哪,可以执行 mvn -v 命令查看 Maven Home 的 bin 目录,setting.xml 文件在与 bin 目录同级的 conf 目录下。

配置 sonatype 系统的账户密码,复制以下配置,修改为自己用户名密码后,添加到 setting.xml 文件中的 … 节点。注意查看节点是否已被注释掉。

<server>
    <!-- id 与 pom.xml 的 distributionManagement -> snapshotRepository 节点中的 id 对应-->
	<id>sonatype-snapshots</id>
	<username>sonatype_username</username>
	<password>sonatype_password</password>
</server>
<server>
    <!-- id 与 pom.xml 的 distributionManagement -> repository 节点中的 id 对应-->
	<id>sonatype-release</id>
	<username>sonatype_username</username>
	<password>sonatype_password</password>
</server>

配置 gpg 的账户密码,复制以下配置,修改为自己的密码后,添加到 setting.xml 文件中的 … 节点。注意查看节点是否已被注释掉。

<profile>
    <!-- id 与 pom.xml 的 maven-gpg-plugin 插件中的 id 对应-->
  <id>ossrh</id>
  <activation>
	<activeByDefault>true</activeByDefault>
  </activation>
  <properties>
	<gpg.executable>gpg</gpg.executable>
	<gpg.passphrase>your_gpg_password</gpg.passphrase>
  </properties>
</profile>

pom.xml

若以下配置节点,有些童鞋不清楚该配置到什么位置的,可以参考下面我的配置示例。

  • 项目 URL 、SCM信息、开发者信息。修改对应值为自己的
<url>https://github.com/wxdfun/bones-spring-boot-tools</url>

<scm>
	<url>https://github.com/wxdfun/bones-spring-boot-tools</url>
	<connection>scm:git:https://github.com/wxdfun/bones-spring-boot-tools.git</connection>
	<developerConnection>scm:git:https://github.com/wxdfun/bones-spring-boot-tools.git</developerConnection>
	<tag>HEAD</tag>
</scm>

<developers>
	<developer>
		<id>wxdfun</id>
		<name>wxdfun</name>
		<email>wxd@wxdfun.com</email>
		<url>https://www.wxdfun.com</url>
		<timezone>+8</timezone>
	</developer>
</developers>

<licenses>
	<license>
		<name>The Apache Software License, Version 2.0</name>
		<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
	</license>
</licenses>
  • Javadoc 和 Source 插件
<!-- Source -->
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-source-plugin</artifactId>
	<version>${maven-source-plugin.version}</version>
	<executions>
		<execution>
			<id>attach-sources</id>
			<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>${maven-javadoc-plugin.version}</version>
	<configuration>
		<show>package</show>
		<tags>
			<tag>
				<name>date</name>
			</tag>
		</tags>
	</configuration>
	<executions>
		<execution>
			<id>attach-javadocs</id>
			<phase>package</phase>
			<goals>
				<goal>jar</goal>
			</goals>
			<configuration>
				<doclint>none</doclint>
			</configuration>
		</execution>
	</executions>
</plugin>
  • GPG 签名插件
<!-- Gpg Signature -->
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-gpg-plugin</artifactId>
	<version>${maven-gpg-plugin.version}</version>
	<executions>
		<execution>
            <!-- id 与 setting.xml 的 gpg 配置中的 id 对应-->
			<id>ossrh</id>
			<phase>verify</phase>
			<goals>
				<goal>sign</goal>
			</goals>
		</execution>
	</executions>
</plugin>
  • Maven 部署流程插件 Nexus Staging Maven
<plugin>
	<groupId>org.sonatype.plugins</groupId>
	<artifactId>nexus-staging-maven-plugin</artifactId>
	<version>${nexus-staging-maven-plugin.version}</version>
	<extensions>true</extensions>
	<configuration>
        <!-- 与 setting.xml 的 server 配置中的 sonatype-release 对应-->
		<serverId>sonatype-release</serverId>
		<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
		<autoReleaseAfterClose>true</autoReleaseAfterClose>
	</configuration>
</plugin>
  • snapshot 快照版和 release 正式版的仓库地址
<distributionManagement>
	<snapshotRepository>
		<id>sonatype-snapshots</id>
		<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
	</snapshotRepository>
	<repository>
		<id>sonatype-release</id>
		<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
	</repository>
</distributionManagement>

由于使用 GPG 生成 Javadoc 和 jar 以及对组件进行签名是一个非常耗时的过程,因此通常将这些执行与常规构建配置隔离开来,并移入配置文件中。然后,当通过激活配置文件执行部署,结构如下:

<profiles>
    <profile> 
        <id>release</id>
        <build>
		    <plugins>
              ...
              maven-source-plugin,
              maven-javadoc-plugin,
              maven-gpg-plugin,
              nexus-staging-maven-plugin
              ...
            </plugins>
        </build>
        distributionManagement
    </profile>
</profiles>
pom.xml 示例

下面是我自己一个项目中的 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>

	<groupId>com.wxdfun</groupId>
	<artifactId>bones-spring-boot-tools</artifactId>
	<version>1.0.0</version>
	<modules>
		<module>bones-spring-boot-loader</module>
		<module>bones-spring-boot-loader-tools</module>
	</modules>
	<name>${project.artifactId}</name>
	<packaging>pom</packaging>
	<description>extension of spring-boot-tools</description>
	<url>https://github.com/wxdfun/bones-spring-boot-tools</url>

	<properties>
		<!--项目编译JDK版本-->
		<maven.compiler.source>8</maven.compiler.source>
		<maven.compiler.target>8</maven.compiler.target>
		<!--项目编码-->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<!--插件版本-->
		<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
		<maven-release-plugin.version>3.0.0-M1</maven-release-plugin.version>
		<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
		<maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
		<nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version>
		<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
		<maven-deploy-plugin.version>3.0.0-M1</maven-deploy-plugin.version>
		<!--spring-boot版本号-->
		<spring-boot.version>2.3.6.RELEASE</spring-boot.version>
	</properties>

	<scm>
		<url>https://github.com/wxdfun/bones-spring-boot-tools</url>
		<connection>scm:git:https://github.com/wxdfun/bones-spring-boot-tools.git</connection>
		<developerConnection>scm:git:https://github.com/wxdfun/bones-spring-boot-tools.git</developerConnection>
		<tag>HEAD</tag>
	</scm>

	<developers>
		<developer>
			<id>wxdfun</id>
			<name>wxdfun</name>
			<email>wxd@wxdfun.com</email>
			<url>https://www.wxdfun.com</url>
			<timezone>+8</timezone>
		</developer>
	</developers>

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

	<repositories>
		<repository>
			<id>ALiYun</id>
			<name>ALiYun</name>
			<url>https://maven.aliyun.com/repository/public</url>
		</repository>
	</repositories>

	<build>
		<finalName>${project.artifactId}-${project.version}</finalName>
		<resources>
			<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>${maven-compiler-plugin.version}</version>
				<configuration>
					<target>${maven.compiler.target}</target>
					<source>${maven.compiler.source}</source>
					<encoding>${project.build.sourceEncoding}</encoding>
					<skip>true</skip>
					<compilerArgs>
						<arg>-parameters</arg>
					</compilerArgs>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<profiles>
		<!--release-->
		<profile>
			<id>release</id>
			<build>
				<plugins>
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-deploy-plugin</artifactId>
						<version>${maven-deploy-plugin.version}</version>
					</plugin>
					<!-- Source -->
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-source-plugin</artifactId>
						<version>${maven-source-plugin.version}</version>
						<executions>
							<execution>
								<id>attach-sources</id>
								<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>${maven-javadoc-plugin.version}</version>
						<configuration>
							<show>package</show>
							<tags>
								<tag>
									<name>date</name>
								</tag>
							</tags>
						</configuration>
						<executions>
							<execution>
								<id>attach-javadocs</id>
								<phase>package</phase>
								<goals>
									<goal>jar</goal>
								</goals>
								<configuration>
									<doclint>none</doclint>
								</configuration>
							</execution>
						</executions>
					</plugin>
					<!-- Gpg Signature -->
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-gpg-plugin</artifactId>
						<version>${maven-gpg-plugin.version}</version>
						<executions>
							<execution>
								<id>ossrh</id>
								<phase>verify</phase>
								<goals>
									<goal>sign</goal>
								</goals>
							</execution>
						</executions>
					</plugin>
					<plugin>
						<groupId>org.sonatype.plugins</groupId>
						<artifactId>nexus-staging-maven-plugin</artifactId>
						<version>${nexus-staging-maven-plugin.version}</version>
						<extensions>true</extensions>
						<configuration>
							<serverId>oss-release</serverId>
							<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
							<autoReleaseAfterClose>true</autoReleaseAfterClose>
						</configuration>
					</plugin>
				</plugins>
			</build>
			<distributionManagement>
				<snapshotRepository>
					<id>sonatype-snapshots</id>
					<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
				</snapshotRepository>
				<repository>
					<id>sonatype-release</id>
					<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
				</repository>
			</distributionManagement>
		</profile>
	</profiles>
</project>

打包发布

完成以上配置,我们就可以往 Maven 中央仓库上传 jar 包了,我们使用 Maven 命令上传。

mvn clean deploy -P release

命令执行期间可能会要求输入证书密码,执行成功后显示如下(该示例是 snapshot 版本):

deploy success

snapshot 和 release 版本区别在于版本号以 -SNAPSHOT 结尾,在 deploy 命令时,发布快照版本。而发布 release 版本的时候,项目版本号不能以 -SNAPSHOT 结尾,插件和依赖项也不能以 -SNAPSHOT结尾。

发布成功之后,则可以在 https://s01.oss.sonatype.org/ 中根据Group Id查找到你发布的 jar 包信息。

search jar

之后我们需要在工单页面留言,标识我们已经发布了第一个版本的 jar 包,激活中央仓库的同步。之后我们便能在 https://repo1.maven.org/maven2/ 中找到我们的 jar 包,阿里云等其他 Maven 仓库都会陆续进行同步。

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值