18、发布与部署:上传到Maven/Ivy仓库、发布到Artifactory/Nexus、签名与校验

说实话,构建做完只是第一步。把产物交到别人手里,才是真本事。

我见过不少团队,Gradle 构建跑得飞起,结果发布环节全靠手动拷贝 jar 包。嗯,这种操作在早期还能忍,项目一多就乱成一锅粥。今天咱们聊聊怎么用 Gradle 把产物发到仓库里,顺便把签名和校验也安排上。

18.1 发布到 Maven 仓库

Maven 仓库是目前 Java 生态最主流的存储方式。Gradle 原生支持发布到 Maven 仓库,靠的是 maven-publish 插件。

核心思路:定义发布组件 → 配置仓库地址 → 执行发布任务。

先看一个最简配置:

plugins {
    id 'java-library'
    id 'maven-publish'
}

publishing {
    publications {
        myLibrary(MavenPublication) {
            from components.java
        }
    }
    repositories {
        maven {
            url = uri('https://your-nexus/repository/maven-releases/')
            credentials {
                username = project.findProperty('repoUser') ?: 'admin'
                password = project.findProperty('repoPass') ?: 'admin123'
            }
        }
    }
}

我个人习惯把用户名密码写在 gradle.properties 里,而不是硬编码。你想想看,万一代码不小心传到公开仓库,密码就全漏了。

小技巧:project.findProperty 读取属性,没找到就用默认值,这样本地开发也能跑。

18.2 发布到 Ivy 仓库

Ivy 仓库现在用得少了,但有些老项目还在用。Gradle 同样支持,用 ivy-publish 插件就行。

plugins {
    id 'java-library'
    id 'ivy-publish'
}

publishing {
    publications {
        ivyJava(IvyPublication) {
            from components.java
        }
    }
    repositories {
        ivy {
            url = uri('https://your-ivy-repo/')
            layout 'pattern', {
                artifact '[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]'
                ivy '[organisation]/[module]/[revision]/ivy-[revision].xml'
            }
        }
    }
}

我在项目中遇到过一个问题:Ivy 的路径模式写错了,导致发布后找不到依赖。后来我学乖了,每次发布完先手动检查一下仓库里的目录结构。

18.3 发布到 Artifactory / Nexus

Artifactory 和 Nexus 都是企业级仓库管理器。它们本质上还是 Maven 或 Ivy 仓库,只是多了 UI 和权限管理。

发布到 Artifactory 时,我建议用它的专用插件:

plugins {
    id 'com.jfrog.artifactory' version '5.1.10'
}

artifactory {
    contextUrl = 'https://artifactory.example.com/'
    publish {
        repository {
            repoKey = 'libs-release-local'
            username = project.findProperty('artifactoryUser')
            password = project.findProperty('artifactoryPass')
        }
        defaults {
            publications('myLibrary')
        }
    }
}

Nexus 的话,直接用 maven-publish 插件就行,它兼容标准 Maven 仓库协议。

注意:Nexus 的 snapshot 和 release 仓库要分开配置。我曾经把 snapshot 发到了 release 仓库,结果 Nexus 直接拒绝覆盖,折腾了半天才搞清楚。

18.4 签名与校验

签名是为了让别人确认这个 jar 确实是你发布的。Maven Central 要求所有上传的构件都必须有 PGP 签名。

Gradle 用 signing 插件来做这件事:

plugins {
    id 'signing'
}

signing {
    sign publishing.publications.myLibrary
}

// 签名密钥配置(写在 gradle.properties 里)
signing.keyId=你的密钥ID
signing.password=你的密钥密码
signing.secretKeyRingFile=路径/到/secring.gpg

嗯,这里要注意:secring.gpg 文件千万别提交到 Git 仓库。我一般把它放在 ~/.gradle/ 目录下,然后在 CI 环境里用环境变量注入。

校验是反过来的过程。Gradle 在依赖解析时会自动校验签名,前提是你配置了正确的公钥服务器:

repositories {
    maven {
        url = uri('https://repo.maven.apache.org/maven2/')
        metadataSources {
            mavenPom()
            artifact()
        }
        // 开启签名校验
        signatureVerification {
            verifySignatures = true
        }
    }
}

避坑指南:我曾经遇到过签名校验失败,原因是公钥没上传到公共密钥服务器。记得用 gpg --keyserver keyserver.ubuntu.com --send-keys 你的密钥ID 上传一下。

18.5 知识体系总览

下面这张图把本章的核心逻辑串起来了:

发布与部署知识体系 Gradle 发布流程 Maven 仓库 Ivy 仓库 Artifactory Nexus PGP 签名 签名校验 发布 = 选择仓库 + 配置工具 + 签名校验

18.6 实战建议

最后给几个我踩过坑之后的经验:

  • 版本号管理:别用 SNAPSHOT 当版本号发到 release 仓库。Nexus 和 Artifactory 都有策略限制,发不上去的。
  • CI/CD 集成:我习惯在 Jenkins 或 GitLab CI 里用 gradle publish 任务,配合 --no-daemon 参数,避免守护进程占用资源。
  • 签名密钥备份:密钥丢了就麻烦了。我一般把 secring.gpg 加密后存到公司的密钥管理服务里。
  • 先测试再发布:publishToMavenLocal 先发到本地仓库验证一下,没问题再发远程。

一句话总结:发布不是终点,是交付的起点。把流程自动化、标准化,才能让团队真正高效协作。

公众号:蓝海资料掘金营,微信 deep3321