19、发布与部署:Maven Central发布、私有仓库发布、Artifactory/Nexus集成、签名与校验

说实话,构建工具做到最后,最爽的一刻是什么?

就是你在终端敲下 gradle publish,然后看着控制台输出 BUILD SUCCESSFUL,你的库被推到了远程仓库,别人一行依赖就能拉下来用。嗯,这个感觉,我做了十年Java,每次还是觉得挺有成就感的。

但发布这件事,坑也不少。我见过太多团队,代码写得挺好,一到发布就翻车——签名不对、校验失败、仓库地址配错、甚至把私密信息泄露到公网。今天这一章,我就把发布与部署的完整链路给你捋一遍。

核心要点:发布不是简单的文件上传,它涉及构建产物、元数据、签名、校验、仓库策略等多个环节。任何一个环节出问题,下游消费者都会直接报错。

Gradle 发布与部署知识体系 Gradle 发布 Maven Central 发布 私有仓库发布 Artifactory / Nexus 签名与校验 OSSRH 账号 Group ID 认证 maven-publish 插件 仓库管理 / 代理 / 快照 Gradle Artifactory 插件 Nexus 3 / 权限控制 GPG 签名 / 密钥管理 校验和 / 完整性验证

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-publishsigning。下面是一个典型的配置模板:

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 发布流程

  1. 执行 gradle publish,构件会被推送到 OSSRH 的 Staging 仓库。
  2. 登录 Sonatype Nexus UI,找到 Staging Repositories。
  3. 选中你的 staging repo,点击 Close,系统会运行一系列校验(包括签名、POM 完整性、Javadoc 等)。
  4. 校验通过后,点击 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