4. 构建工具选择:Maven / Gradle / npm

CI 流水线里的第一关,往往就是构建。说白了,你要先把代码变成能跑的东西。工具选不对,后面全是坑。我早期带团队时,就因为一个项目混用了 Maven 和 Gradle 的插件版本,CI 上跑了整整两个钟头没跑通。后来我养成了一个习惯:在搭建流水线之前,先把构建工具定死。

4.1 Maven:稳重但有点啰嗦的老大哥

Maven 的特点是“约定优于配置”。你只要把项目结构摆好,它自己就知道怎么编译、测试、打包。pom.xml 里声明依赖,它就去中央仓库拉。很多 Java 老项目都用它。

适用场景:标准 Java 项目、Spring Boot 应用、需要严格遵循生命周期规范的企业级项目。

我在一个金融项目里遇到过 Maven 的依赖地狱。两个 jar 包冲突,CI 上每次构建都跑错。后来用了 mvn dependency:tree 才揪出罪魁祸首。

<!-- pom.xml 典型配置 -->
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0.0</version>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.0</version>
  </parent>
</project>
避坑指南:我曾经因为 pom.xml 里写死了 snapshot 版本,导致 CI 每次构建都去拉快照,网络不好就超时。建议在 CI 阶段用 -U 强制更新快照,但别默认开启。

4.2 Gradle:快,灵活,但别让它“灵活”过头

Gradle 用的是 Groovy 或 Kotlin DSL,比 Maven 那种 XML 清爽多了。它支持增量编译,只改一个类只重编那个类,CI 上构建速度能快一倍。Android 项目基本全是 Gradle。

我个人习惯在 Gradle 里用 buildCache,尤其是在多模块项目里。有一次我们 CI 上跑 40 个模块,没开缓存,每次全量编译花了 12 分钟。开了之后缩到 4 分钟。

// build.gradle.kts 片段
plugins {
    java
    id("org.springframework.boot") version "3.2.0"
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}

tasks.withType<Test> {
    useJUnitPlatform()
}
小技巧:在 CI 配置文件里加上 --build-cache 参数,配合远程缓存(比如 Redis)效果更好。但记得先跑一遍完整构建预热缓存。

不过 Gradle 太灵活了,有些团队会写出各种自定义 Task,最后连构建顺序都理不清。你想想看,一个 Task 里加了 dependsOn,另一个又 mustRunAfter,相互嵌套,调试起来头都大。我的建议是:能用插件解决的,就别自己写 Task。

4.3 npm:前端的标配,但锁文件要盯紧

Node.js 项目里,npm 基本是事实标准。package.json 定义依赖和脚本,CI 上跑 npm ci 代替 npm install,能保证一致性且更快。

注意:npm ci 依赖 package-lock.json,如果锁文件没提交到 Git,CI 会直接失败。我一个同事就因为这个,每次构建版本都不一样……
{
  "name": "my-frontend",
  "scripts": {
    "build": "vite build",
    "test": "vitest run",
    "lint": "eslint src/"
  },
  "devDependencies": {
    "vite": "^5.0.0",
    "vitest": "^1.0.0"
  }
}
避坑指南:我曾经在 CI 里不加 --no-audit 参数,每次构建还要跑安全审计,拖慢 3 分钟。后来加上了 npm ci --no-audit --no-fund,速度明显提升。如果你需要审计,单独在另外的流水线阶段做。

4.4 选型对比一览

下面这个表格是我多年经验总结的,你直接拿去用就行:

特性MavenGradlenpm
语法稿XML 声明式Groovy / Kotlin 编程式JSON + 脚本
构建速度中等(全量编译为主)快(增量编译 + 缓存)中等(取决于依赖树)
学习曲线低(约定多,配置少)中高(DSL 灵活,但也复杂)低(只用脚本就够)
生态Java 领域极强Java + Android 标准Node.js / 前端统治
CI 配置复杂度低(直接跑 mvn 命令)中(需要调参数)低(npm ci 搞定)
推荐项目企业 Java、Spring 单体Android、大型多模块 Java前端、Node.js 服务、全栈

4.5 构建工具知识图谱

下面这张图帮你理清选择逻辑:从项目类型出发,看语言和生态,最终落到工具上。箭头上的灰色标签是场景说明。

构建工具选型决策图 项目类型 纯 Java Android Node.js / 前端 Maven Gradle npm / yarn / pnpm 单体 / 标准企业 大型模块 / 需增量 mvn clean verify gradle build --build-cache npm ci --no-audit 包管理器选择 yarn pnpm npm 💡 小提示:一个项目也可能同时用多种工具(如后端 Maven + 前端 npm),建议分开流水线阶段

说实话,没有银弹。我见过一个团队固执地用 Maven 做 Android 项目,结果配置极其痛苦,后来换 Gradle 才轻松。也见过有人用 Gradle 写一个只有 3 个类的简单服务,杀鸡用牛刀。嗯,这里要记住:选工具不是炫技,而是看你的项目规模、团队熟悉度和 CI 环境支持。