19、发布与部署:Maven Central发布、私有仓库发布、Artifactory/Nexus集成、签名与校验
说实话,构建工具做到最后,最爽的一刻是什么?
就是你在终端敲下 gradle publish,然后看着控制台输出 BUILD SUCCESSFUL,你的库被推到了远程仓库,别人一行依赖就能拉下来用。嗯,这个感觉,我做了十年Java,每次还是觉得挺有成就感的。
但发布这件事,坑也不少。我见过太多团队,代码写得挺好,一到发布就翻车——签名不对、校验失败、仓库地址配错、甚至把私密信息泄露到公网。今天这一章,我就把发布与部署的完整链路给你捋一遍。
核心要点:发布不是简单的文件上传,它涉及构建产物、元数据、签名、校验、仓库策略等多个环节。任何一个环节出问题,下游消费者都会直接报错。
19.1 Maven Central 发布——从本地到全球
Maven Central 是 Java 生态里最权威的公共仓库。你的库如果能发布到 Central,意味着全球开发者都能通过一行 implementation 直接引用。
但这条路,说实话,门槛不低。我最早发布第一个开源库的时候,光申请 OSSRH 账号就折腾了两天。
19.1.1 准备工作
- 注册 OSSRH 账号:访问 Sonatype JIRA,创建一个项目,申请 Group ID 的所有权。通常需要提供 GitHub 仓库地址或域名证明。
- 验证 Group ID:如果你用
com.github.xxx,需要证明你拥有该 GitHub 账号。如果你用com.yourcompany,需要证明域名所有权。 - 生成 GPG 密钥:所有发布到 Central 的构件都必须经过签名。用
gpg --gen-key生成密钥对,然后上传公钥到公共密钥服务器。
我的经验:GPG 密钥的密码一定要记牢。我曾经因为换电脑忘了导出私钥,结果一个旧库没法更新,只能重新申请 Group ID。嗯,血的教训。
19.1.2 Gradle 配置
你需要两个插件:maven-publish 和 signing。下面是一个典型的配置模板:
plugins {
id 'java-library'
id 'maven-publish'
id 'signing'
}
java {
withJavadocJar()
withSourcesJar()
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom {
name = 'My Library'
description = 'A useful library for something'
url = 'https://github.com/yourname/mylib'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'yourid'
name = 'Your Name'
email = 'your@email.com'
}
}
scm {
connection = 'scm:git:git://github.com/yourname/mylib.git'
developerConnection = 'scm:git:ssh://github.com:yourname/mylib.git'
url = 'https://github.com/yourname/mylib'
}
}
}
}
repositories {
maven {
def releasesRepoUrl = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'
def snapshotsRepoUrl = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = project.findProperty('ossrhUsername') ?: ''
password = project.findProperty('ossrhPassword') ?: ''
}
}
}
}
signing {
sign publishing.publications.mavenJava
}
注意:千万不要把 OSSRH 的用户名密码硬编码在 build.gradle 里。我建议放在 ~/.gradle/gradle.properties 中,或者通过 CI 环境变量注入。
19.1.3 发布流程
- 执行
gradle publish,构件会被推送到 OSSRH 的 Staging 仓库。 - 登录 Sonatype Nexus UI,找到 Staging Repositories。
- 选中你的 staging repo,点击 Close,系统会运行一系列校验(包括签名、POM 完整性、Javadoc 等)。
- 校验通过后,点击 Release。大约 15 分钟后,你的库就会出现在 Maven Central 上。
为什么会需要 Close 这一步?说白了,这是 Central 的审核机制。它确保每个发布的构件都是完整且可用的,不会出现「下载了一半发现缺文件」的情况。
19.2 私有仓库发布——企业内部的最佳实践
很多公司不会把内部库发到 Maven Central。原因很简单:商业代码、敏感逻辑、或者还没准备好公开。这时候,私有仓库就是你的选择。
我个人习惯在公司内部搭建 Nexus 或 Artifactory,然后通过 Gradle 直接发布。配置其实比 Central 简单得多——不需要 GPG 签名,也不需要 POM 的完整信息。
publishing {
publications {
myLibrary(MavenPublication) {
from components.java
groupId = 'com.company.internal'
artifactId = 'my-internal-lib'
version = '1.2.3'
}
}
repositories {
maven {
name = 'internal'
url = 'http://nexus.company.com/repository/internal-releases/'
credentials {
username = project.findProperty('nexusUser') ?: ''
password = project.findProperty('nexusPass') ?: ''
}
}
}
}
避坑指南:我曾经遇到过一个团队,把快照版本和正式版本发到了同一个仓库目录,结果导致依赖解析混乱。建议严格区分 releases 和 snapshots 两个仓库,Gradle 的 version 以 -SNAPSHOT 结尾时会自动匹配快照仓库。
19.3 Artifactory / Nexus 集成——企业级仓库管理
Artifactory 和 Nexus 都是成熟的二进制仓库管理器。它们不仅能存 Maven 构件,还能存 Docker 镜像、npm 包、PyPI 包等。对于 Java 团队来说,它们主要做三件事:
- 代理远程仓库:把 Maven Central、JCenter 等缓存到本地,加速构建。
- 托管私有构件:内部库、第三方商业库、带 license 的 jar 包。
- 权限控制:哪些团队能发布,哪些只能读取,都可以精细配置。
19.3.1 Gradle 集成 Artifactory
Artifactory 官方提供了 Gradle 插件,配置起来非常直接:
plugins {
id 'java-library'
id 'maven-publish'
id 'com.jfrog.artifactory' version '5.1.10'
}
artifactory {
contextUrl = 'https://artifactory.company.com'
publish {
repository {
repoKey = 'libs-release-local'
username = project.findProperty('artifactoryUser')
password = project.findProperty('artifactoryPass')
}
defaults {
publications('mavenJava')
publishArtifacts = true
publishPom = true
}
}
resolve {
repository {
repoKey = 'libs-release'
username = project.findProperty('artifactoryUser')
password = project.findProperty('artifactoryPass')
}
}
}
你只需要执行 gradle artifactoryPublish,插件会自动处理上传、元数据生成、以及仓库间的同步。
19.3.2 Nexus 3 集成
Nexus 3 不提供专门的 Gradle 插件,但你可以直接用 maven-publish 配合它的 REST API。Nexus 的仓库 URL 格式通常是:
http://nexus:8081/repository/maven-releases/
http://nexus:8081/repository/maven-snapshots/
配置方式和前面私有仓库的例子完全一样。唯一要注意的是,Nexus 3 默认开启了 Staging 功能,发布后需要手动或通过脚本 promote 才能正式可用。
我的建议:如果团队规模不大(10人以内),用 Nexus 3 就够了,免费且稳定。如果团队超过 50 人,或者需要多语言构件管理,Artifactory 的 Pro 版会更省心——它的元数据搜索和权限模型确实更强。
19.4 签名与校验——信任的最后一道防线
签名不是为了炫技,而是为了证明「这个 jar 确实是你发布的,没有被篡改过」。Maven Central 强制要求签名,私有仓库虽然不强制,但我建议你也加上。
19.4.1 GPG 签名原理
简单来说:你用私钥对 jar 包生成一个 .asc 签名文件,消费者用你的公钥验证签名。如果 jar 包被中间人替换,签名校验就会失败。
// 在 build.gradle 中启用签名
signing {
useGpgCmd() // 使用系统安装的 gpg 命令
sign publishing.publications.mavenJava
}
你需要在 gradle.properties 中配置密钥信息:
signing.keyId=你的密钥ID(8位十六进制)
signing.password=密钥密码
signing.secretKeyRingFile=/path/to/secring.gpg
注意:GPG 2.1 之后不再生成 secring.gpg 文件。如果你用的是新版 GPG,需要用 gpg --export-secret-keys -o secring.gpg 手动导出。我当初在这个问题上卡了整整一个下午。
19.4.2 校验和验证
除了签名,Gradle 还会自动生成 .md5、.sha1、.sha256 等校验文件。消费者在下载时,Gradle 会自动比对校验和,确保文件没有损坏。
你可以通过以下配置自定义校验算法:
publishing {
publications {
mavenJava(MavenPublication) {
pom.withXml {
asNode().appendNode('checksums').appendNode('sha256')
}
}
}
}
说实话,校验和这个环节很多人会忽略。但我在生产环境中遇到过因为网络传输丢包导致 jar 包损坏的情况,如果没有校验和,那个 bug 可能要排查好几天。
19.5 综合建议与常见问题
| 场景 | 推荐方案 | 注意事项 |
|---|---|---|
| 开源库发布 | Maven Central + GPG 签名 | OSSRH 审核周期约 1-2 天 |
| 公司内部库 | Nexus 3 或 Artifactory | 区分 releases/snapshots 仓库 |
| 多团队协作 | Artifactory Pro | 配置细粒度权限和仓库视图 |
| CI/CD 集成 | Gradle + Jenkins/GitHub Actions | 凭据通过 CI 变量注入,不要写死 |
最后一个小技巧:发布前先用 gradle publishToMavenLocal 测试一遍,确认本地能正常安装和使用。这一步能帮你发现 90% 的配置问题,比如 POM 缺少依赖、Javadoc 生成失败等。
发布与部署,说白了就是把你本地的劳动成果,安全、完整地交付给使用者。工具只是手段,真正重要的是你对整个链路的理解——从签名到校验,从仓库策略到权限控制。嗯,把这些都吃透了,你就能自信地说:我的库,别人用得放心。
公众号:蓝海资料掘金营,微信deep3321