说明
很多时候,我们开发的构件需要上传到maven私服,以便团队中其他人使用。但在开源社区,例如github上托管的项目,如果希望给其他人使用就不能发布到私服了,最好的选择当然是maven官方的中央仓库。具体怎么做呢?
操作步骤
操作步骤宏观上大致分为三个: 1. 官方工单申请;2,gpg密钥设置和公钥上传 2. 项目配置(setting.xml和pom.xml);3. 执行发布
官方工单申请
官方工单申请地址为: issues.sonatype.org。
若未注册,需要先注册。注册后的具体步骤网上教程很多,可以参考这篇:一键搞定发布自己Jar到Maven中央仓库。
这里有几点注意事项:
- 工单处理时效还是蛮快的,几个小时或次日就有消息了。
- 我开始groupId随便取的,没通过,他评论建议我使用
io.github.*
, 因此我使用了io.github.pengxianggui
。 - 工单里的groupId必须和pom.xml中的groupId保持一致,否则后续推不上去(为此我改了项目中的groupId)。
- groupId非常重要,一旦审核通过就改不了,要改只能重新提单子。所以非必要不要变。
- 工单审核通过后,评论里会给进一步的指导。
- 审核通过后,别忘了关闭工单。
- sonatype的账密千万别忘了,后面要配置到settings.xml里的。
这是我操作时申请的工单,可以参考。
gpg密钥配置
gpg的作用大概是为你的构件(jar)进行加密,防止deploy传输中被篡改。
安装
因为我是mac, 命令行可以直接安装: brew install gpg2
。如果是win,可以下载后安装(可参考上面那篇博客)。
也可以下载后安装,这里附上下载地址和操作指南: mac获取maven-gpg-key, 操作指南基本也是下面命令行的可视化替代而已。
❗️ 注意: 如果使用上面下载的软件可视化操作,下面这些命令行步骤就可以跳过了。
生成密钥
gpg --gen-key
会提醒你输入姓名、邮箱、密码等。输入后,直接回车。
命令查看密钥
gpg --list-keys
可以看到,我刚刚生成的密钥,pub 下 一串16进制数是密钥ID。
上传至公钥服务器
gpg --keyserver keyserver.ubuntu.com --send-keys 秘钥ID
通过这句命令将指定的密钥对应的公钥上传至公钥服务器。
❗️注意:这个命令可能会失败。或是网络问题,或是这个地址不可用。这时有个备用方法,那就是直接到https://keyserver.ubuntu.com/# 去,在页面上上传公钥。
具体操作如下:
❓上面的那一大串公钥是哪里来的呢?使用下面的命令查看密钥的公钥:
gpg -a -o public.key --export 密钥ID
公钥会被导出到public.key,用文本编辑器查看复制出来,就是上面的一大串内容了。
❗️注意: 上传完毕后,要确认下能否查到。具体方法:
访问这个地址: https://keys.openpgp.org, 然后输入你刚刚填写的邮箱,即可查询。
上图中马赛克遮住的部分其实就是上面的密钥ID。
至此,gpg准备部分就算了结了。
上面讲的两种方式,更推荐下载软件安装的方式,而不是命令行。原因有二:
- 上传公钥时,可以直接在软件里自动提示你完整,一个按钮即可,不会有网络问题;
- 可以方便的设置过期时间;
项目配置(setting.xml和pom.xml)
settings.xml配置
<!-- 针对特定服务器指定认证信息。ossrh是Sonatype OSS Repository Hosting的简称。
在应用此settings.xml的项目的pom.xml中,distributionManagement里需要保证id相同。
才能在发布时应用此账密。 -->
<server>
<id>ossrh</id>
<!-- 下面的账密,必须是之前在sonatype里注册的 -->
<username>******</username>
<password>******</password>
</server>
<profiles>
<!-- 发布到maven中央仓库。项目install时需勾选ossrh, 才能deploy到中央仓库 -->
<profile>
<!-- 这个id值其实跟上面的server里的id不必相同 -->
<id>ossrh</id>
<!-- 这里设置这些properties是为了pom.xml中引用 -->
<properties>
<!-- 这是利用gpg插件加密时调用gpg的命令 -->
<gpg.executable>gpg2</gpg.executable>
<!-- 前面生成gpg密钥ID时设置的密码,如果不设置这个,执行时会交互式让你输入密码 -->
<gpg.passphrase>***</gpg.passphrase>
<!-- 前面生成的gpg 密钥对应的签名短 keyid,如何获取看下面批注 -->
<gpg.keyname>***</gpg.keyname>
<!-- gpg密钥文件位置,一般默认为 ~/.gnupg,保险起见填写绝对路径 -->
<gpg.homedir>/Users/pengxianggui/.gnupg</gpg.homedir>
</properties>
</profile>
</profiles>
❗️【注意】:
- 上面profiles的内容也可以写到pom.xml里。但是考虑到其中有gpg的一些敏感信息,写到settings.xml里了。
- 上面gpg.keyname的值如何获取呢,可以看官网说明, 重点看下面截图这个部分:
pom.xml 配置
如果要上传maven中央仓库,pom.xml里有几个部分是非常重要的(必不可少):
- description和url必不可少
- licenses: 指定项目的开源许可证信息。
- scm: 主要作用是指定项目的源代码版本控制系统,以便maven插件与版本控制系统交互,执行一些与版本控制相关的操作。这些操作包括标记版本、生成发布说明、检查出指定版本等。
- developers: 指定开发者信息。
- distributionManagement: 用于配置如何分发项目构建产物(例如 JAR 文件)到不同的 Maven 仓库或其他目标。这个元素定义了项目构建的部署配置,包括发布到中央仓库或私有仓库的规则和位置。
我的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>io.github.pengxianggui</groupId>
<artifactId>db-metadata-parent</artifactId>
<version>2.4.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>db-metadata-parent</name>
<description>A Low-code development framework base on data-drive</description>
<url>https://github.com/pengxianggui/db-metadata</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 指定maven编译的java项目是java8。有这两个,一般就无需 maven-compiler-plugin了 [start]-->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- ********************************************************************* [end]-->
</properties>
<modules>
<module>./db-metadata-interface</module>
<module>./db-metadata-server-springboot</module>
<module>./db-metadata-analysis-springboot</module>
<module>./db-metadata-extends</module>
</modules>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<connection>scm:git:git@github.com:pengxianggui/db-metadata.git</connection>
<developerConnection>scm:git:git@github.com:pengxianggui/db-metadata.git</developerConnection>
<url>https://github.com/pengxianggui/db-metadata</url>
<tag>v@{project.version}</tag>
</scm>
<developers>
<developer>
<name>XiangGui Peng</name>
<email>pengxianggui@outlook.com</email>
<timezone>+8</timezone>
</developer>
</developers>
<pluginRepositories>
<pluginRepository>
<id>maven-ali</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<!-- 配置maven远程仓库,若本地找不到,则会从这里配置的远程仓库寻找依赖,最后是中央仓库 -->
<repositories>
<repository>
<id>maven-ali</id>
<name>阿里云远程maven仓库</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<layout>default</layout> <!--用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)-->
<releases>
<enabled>true</enabled> <!--可从此仓库下载releases版本的依赖-->
</releases>
<snapshots>
<enabled>false</enabled> <!--禁止从此仓库下载shapshots版本的依赖,公共仓库的snapshot版本往往不稳定且不受控制-->
<!-- <updatePolicy>always</updatePolicy>--> <!-- 上面设置为false后,这两条配置就没意义了,注释掉 -->
<!-- <checksumPolicy>warn</checksumPolicy>-->
</snapshots>
</repository>
</repositories>
<!-- 配置打包发布的远程仓库 -->
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<name>Nexus Release Repository</name>
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<pluginManagement>
<plugins>
<!-- 生成项目的源代码 JAR 文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<id>attach-source</id>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- javadoc文档生成插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<!-- jdk1.8要加上: 防止注释中的非标准标记(如@date) -->
<additionalJOptions>
<additionalJOption>-Xdoclint:none</additionalJOption>
</additionalJOptions>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- release plugin,用于发布到release仓库部署插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<tagNameFormat>v@{project.version}</tagNameFormat>
<autoVersionSubmodules>true</autoVersionSubmodules>
<arguments>-DskipTests</arguments>
<!-- <!– 手动push。 release:prepare执行时总是无法自动push代码,这里改为手动。在-->
<!-- release:prepare 执行完毕后,手动push(tag也要), 再执行 release:perform–>-->
<!-- <pushChanges>false</pushChanges>-->
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
</plugin>
<!-- gpg加密 -->
<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>
<configuration>
<keyname>${gpg.keyname}</keyname>
<passphrase>${gpg.passphrase}</passphrase>
<passphraseServerId>${gpg.keyname}</passphraseServerId>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
<homedir>${gpg.homedir}</homedir>
</configuration>
</execution>
</executions>
</plugin>
<!-- 自动close、release -->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</project>
完整的pom.xml可以查看这里: pom.xml。
重点关注我的pom里关于上面提到的这些部分。另外我的pom.xml里还涉及到maven-release-plugin的应用,关于这个插件,我也摸索了一遍,踩了些坑,后面单独篇幅去记录。
使用
上面的步骤就已经完成了所有准备了。接下来,就运行clean deploy发布就行了!具体操作就一句话:
勾选ossrh,点选clean和deploy,然后run即可
,图示:
勾选ossrh的目的是为了应用settings.xml里那个id为ossrh的profile的配置
踩坑
- 工单填写时设置的groupId不能太随意,是有限制的,而且必须和项目里的groupId完全一致。
- gpg那个步骤省不了,但是我似乎发现发布SNAPSHOT版本时可以不要那个步骤(这一点没有确认过,不过这个总归省不了的)
- gpg公钥上传死活上不去,命令行各种报错,什么“No route", 或者网络问题… 最后是一个文章里找到的,可以在页面上传这个公钥,才解决问题。感谢那位不知名博主!(找不到记录了)。但后来抱着死磕的态度,又试了一次下载软件,相当顺利,所以更推荐下载软件。
- pom.xml里scm里的那几个url不要写错了,或者乱写;project下的description和url一定要写;
- pom.xml里的distributionManagement中的id一定要和settings.xml里配置的server那个匹配。相当于通过这个id,将pom.xml里的地址,和settings.xml里的账密对应上。maven才能正确使用账密去发布到这个地址。并且snapshotRepository和repository的id可以相同。
- 发布成功后,不是立马就能在maven中央仓库看到的,需要等几个小时。国内镜像就更延迟一些了。
- 上面pom.xml里nexus-staging-maven-plugin这个插件的作用自动close、release和drop。如果autoReleaseAfterClose设置为false, 或者仓库那边验证失败, 可能需要登录https://s01.oss.sonatype.org/#stagingRepositories手动操作。
- https://s01.oss.sonatype.org 和 https://oss.sonatype.org 有什么区别?其实只是多个节点而已,可能以后还会有s02, s03,至于用哪个地址,取决于jira工单审核通过后,他给你的评论里,会告诉你地址的。那么pom.xml里就统一用这个地址。
- nexus sonatype manager 的登录也是一样的,jira里给你的是哪个地址,你也得登录哪个地址去管理。比如给我的是https://s01.oss.sonatype.org,我后来不小心登录了https://oss.sonatype.org,死活登录不上,提示账密错误或者无权限,折腾半天。