📚 本系列系统梳理了 Java 开发的详细知识点,从基础语法到工程实践层层递进,内容详实成体系,建议先收藏再慢慢阅读,方便日后随时回顾查阅。

前言

Java 项目不像 Python 那样一个 .py 文件就能跑——真实项目涉及依赖管理、编译、测试、打包、发布等一系列工程化流程。构建工具就是把这些事情自动化的基础设施。这篇文章把 Maven 和 Gradle 两个主流工具都讲清楚,重点放在日常开发中最常用的操作。

1. 为什么需要构建工具?

一个真实的 Java 项目,手动操作会是这样:

1. 去各个网站下载依赖 jar 包,放到 lib 目录
2. javac -cp lib/*.jar src/**/*.java -d out/
3. 跑测试:java -cp out:lib/* org.junit.runner.JUnitCore ...
4. 打 jar 包:jar cvf app.jar -C out/ .
5. 部署到服务器
6. 依赖更新了?重新下载,重复上面所有步骤...

构建工具做的事情就是:用一个配置文件描述项目结构和依赖,然后一条命令搞定所有。

2. Maven

2.1 核心概念

Maven 的哲学是约定优于配置——它预定义了标准的项目结构和构建流程,你只需要写一个 pom.xml 描述项目信息和依赖。

标准项目结构:

my-project/
├── pom.xml                  ← 项目配置文件(核心)
├── src/
│   ├── main/
│   │   ├── java/            ← 源代码
│   │   │   └── com/example/
│   │   │       └── App.java
│   │   └── resources/       ← 配置文件(application.yml 等)
│   └── test/
│       ├── java/            ← 测试代码
│       └── resources/       ← 测试配置
└── target/                  ← 编译输出(自动生成)

2.2 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>com.example</groupId>       <!-- 组织/公司(反转域名) -->
    <artifactId>my-app</artifactId>      <!-- 项目名 -->
    <version>1.0.0</version>             <!-- 版本号 -->
    <packaging>jar</packaging>           <!-- 打包方式:jar / war / pom -->

    <!-- 属性:集中管理版本号和配置 -->
    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>3.2.0</spring-boot.version>
    </properties>

    <!-- 依赖声明 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>   <!-- 只在测试时使用 -->
        </dependency>
    </dependencies>
</project>

2.3 坐标(GAV)

每个 Maven 依赖由三个要素唯一确定:

groupId:artifactId:version
<!-- 就像收件地址:国家:城市:门牌号 -->
<groupId>com.google.guava</groupId>     <!-- 谁开发的 -->
<artifactId>guava</artifactId>           <!-- 叫什么名字 -->
<version>32.1.3-jre</version>            <!-- 哪个版本 -->

去哪找坐标?Maven Centralmvnrepository.com,搜索库名直接复制 XML 片段。

2.4 依赖范围(Scope)

Scope 编译 测试 运行 打包 典型依赖
compile(默认) Spring、Guava
test JUnit、Mockito
provided Servlet API(容器提供)
runtime JDBC 驱动
system 本地 jar(不推荐)
<!-- JUnit 只在测试时用 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

<!-- MySQL 驱动:编译时不需要,运行时才加载 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.2.0</version>
    <scope>runtime</scope>
</dependency>

2.5 依赖传递与冲突

你的项目 → 依赖 A → 依赖 C 1.0
你的项目 → 依赖 B → 依赖 C 2.0

Maven 的解决策略:最短路径优先,路径相同时先声明优先

<!-- 如果自动选择的版本不对,可以手动排除 + 显式指定 -->
<dependency>
    <groupId>com.example</groupId>
    <artifactId>lib-a</artifactId>
    <version>1.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.example</groupId>
            <artifactId>lib-c</artifactId>  <!-- 排除 A 传递过来的 C -->
        </exclusion>
    </exclusions>
</dependency>

<!-- 显式声明你要用的版本 -->
<dependency>
    <groupId>com.example</groupId>
    <artifactId>lib-c</artifactId>
    <version>2.0</version>
</dependency>

查看依赖树,排查冲突:

mvn dependency:tree
# 会打印完整的依赖树,显示每个依赖是怎么传递进来的

2.6 生命周期与常用命令

Maven 定义了三套生命周期,最常用的是 default:

validate → compile → test → package → verify → install → deploy

每个阶段包含前面所有阶段,执行某个阶段会自动执行它前面的所有阶段:

# 编译
mvn compile

# 运行测试
mvn test

# 打包(编译 + 测试 + 打 jar/war)
mvn package

# 安装到本地仓库(~/.m2/repository),其他本地项目可以依赖它
mvn install

# 清理 target 目录
mvn clean

# 最常用的组合
mvn clean package              # 清理 + 打包
mvn clean package -DskipTests  # 跳过测试打包(赶时间用)
mvn clean install              # 清理 + 打包 + 安装到本地

# 查看有效 POM(合并了父 POM 和默认配置后的完整配置)
mvn help:effective-pom

# 查看依赖树
mvn dependency:tree

2.7 Maven 仓库

本地仓库(~/.m2/repository/)
  ↑ 找不到就去远程下载
中央仓库(repo.maven.apache.org)
  ↑ 或者公司的私服
私服(Nexus / Artifactory)

配置阿里云镜像加速(~/.m2/settings.xml):

<mirrors>
    <mirror>
        <id>aliyun</id>
        <mirrorOf>central</mirrorOf>
        <name>Aliyun Maven Mirror</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
</mirrors>

2.8 继承与多模块

大型项目通常拆分为多个模块:

parent-project/
├── pom.xml                    ← 父 POM(packaging: pom)
├── common/
│   ├── pom.xml
│   └── src/
├── service/
│   ├── pom.xml
│   └── src/
└── web/
    ├── pom.xml
    └── src/

父 POM 统一管理版本:

<!-- 父 POM -->
<project>
    <groupId>com.example</groupId>
    <artifactId>parent-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>common</module>
        <module>service</module>
        <module>web</module>
    </modules>

    <!-- dependencyManagement:声明版本但不引入,子模块按需引用时不用写版本号 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>32.1.3-jre</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

<!-- 子模块 POM -->
<project>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>parent-project</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>service</artifactId>

    <dependencies>
        <!-- 不用写 version,从父 POM 的 dependencyManagement 继承 -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </dependency>
    </dependencies>
</project>

3. Gradle

3.1 Gradle vs Maven

维度 Maven Gradle
配置文件 pom.xml(XML) build.gradle(Groovy)或 build.gradle.kts(Kotlin)
配置风格 声明式、冗长 声明式 + 编程式、简洁
构建速度 较慢 快(增量编译 + 构建缓存 + 守护进程)
灵活性 低(约定严格,自定义需写插件) 高(配置文件本身就是代码,随时写逻辑)
学习曲线 低(XML 直白) 较高(需要了解 Groovy/Kotlin DSL)
主要用户 传统企业项目、Spring 生态 Android(官方)、新项目、Spring Boot
IDE 支持 IntelliJ / Eclipse 都很好 IntelliJ 很好,Eclipse 一般

怎么选? 新项目优先 Gradle(更快更灵活),维护老项目用 Maven 也完全没问题。Spring Boot 官方同时支持两者。

3.2 标准项目结构

和 Maven 一样(Gradle 也遵循约定优于配置):

my-project/
├── build.gradle               ← 构建配置
├── settings.gradle            ← 项目设置(名称、子模块)
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew                    ← Linux/Mac 构建脚本
├── gradlew.bat                ← Windows 构建脚本
└── src/
    ├── main/java/
    ├── main/resources/
    ├── test/java/
    └── test/resources/

3.3 build.gradle 详解(Groovy DSL)

plugins {
    id 'java'                                    // Java 插件
    id 'org.springframework.boot' version '3.2.0' // Spring Boot 插件
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.example'
version = '1.0.0'

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenLocal()          // 先找本地仓库
    maven { url 'https://maven.aliyun.com/repository/public' }  // 阿里云镜像
    mavenCentral()        // Maven 中央仓库
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.google.guava:guava:32.1.3-jre'

    compileOnly 'org.projectlombok:lombok:1.18.30'
    annotationProcessor 'org.projectlombok:lombok:1.18.30'

    runtimeOnly 'com.mysql:mysql-connector-j:8.2.0'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

3.4 Kotlin DSL(build.gradle.kts)

plugins {
    java
    id("org.springframework.boot") version "3.2.0"
    id("io.spring.dependency-management") version "1.1.4"
}

group = "com.example"
version = "1.0.0"

java {
    sourceCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("com.google.guava:guava:32.1.3-jre")
    runtimeOnly("com.mysql:mysql-connector-j:8.2.0")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.test {
    useJUnitPlatform()
}

Kotlin DSL 的好处:IDE 自动补全和类型检查更好。新项目推荐用 .kts

3.5 依赖配置(对比 Maven Scope)

Gradle 配置 对应 Maven Scope 说明
implementation compile 编译 + 运行时需要,不传递给依赖此模块的项目
api compile 编译 + 运行时需要,传递给依赖此模块的项目(需要 java-library 插件)
compileOnly provided 只在编译时需要(如 Lombok、Servlet API)
runtimeOnly runtime 只在运行时需要(如 JDBC 驱动)
testImplementation test 只在测试时需要
annotationProcessor 无直接对应 注解处理器(如 Lombok、MapStruct)

implementation vs api 是 Gradle 最容易混淆的点:

// 模块 A 依赖 Guava
// 模块 B 依赖 模块 A

// 如果模块 A 用 implementation:
//   模块 B 看不到 Guava(编译隔离,防止泄露内部实现细节)

// 如果模块 A 用 api:
//   模块 B 也能直接用 Guava(适合库开发,对外暴露的 API 中用到的依赖)

// 原则:默认用 implementation,只有依赖出现在你的 public API 中才用 api

3.6 常用命令

# 编译
./gradlew compileJava

# 运行测试
./gradlew test

# 打包
./gradlew build                  # 编译 + 测试 + 打包
./gradlew build -x test          # 跳过测试

# 清理
./gradlew clean

# 查看依赖树
./gradlew dependencies
./gradlew dependencies --configuration runtimeClasspath  # 只看运行时依赖

# Spring Boot 直接运行
./gradlew bootRun

# 查看所有可用任务
./gradlew tasks

始终用项目自带的 ./gradlew(Gradle Wrapper)而不是全局的 gradle,保证团队使用相同的 Gradle 版本。

3.7 Gradle Wrapper

# 项目自带的 Wrapper 脚本,保证版本一致
./gradlew build         # Linux/Mac
gradlew.bat build       # Windows

# 升级 Wrapper 版本
./gradlew wrapper --gradle-version 8.5

# gradle-wrapper.properties 中的配置
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip

3.8 多模块项目

parent-project/
├── build.gradle           ← 根项目配置
├── settings.gradle        ← 声明子模块
├── common/
│   └── build.gradle
├── service/
│   └── build.gradle
└── web/
    └── build.gradle
// settings.gradle
rootProject.name = 'parent-project'
include 'common', 'service', 'web'
// 根 build.gradle:对所有子模块统一配置
subprojects {
    apply plugin: 'java'

    group = 'com.example'
    version = '1.0.0'

    java {
        sourceCompatibility = JavaVersion.VERSION_17
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
    }

    test {
        useJUnitPlatform()
    }
}
// service/build.gradle:子模块依赖另一个子模块
dependencies {
    implementation project(':common')  // 依赖 common 模块
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

4. 版本管理:BOM 与版本目录

4.1 BOM(Bill of Materials)

统一管理一组依赖的版本,避免版本冲突:

<!-- Maven:使用 Spring Boot BOM -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 之后声明 Spring 相关依赖不用写版本号 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 版本由 BOM 统一控制 -->
    </dependency>
</dependencies>
// Gradle:使用 Spring 的 dependency-management 插件自动导入 BOM
plugins {
    id 'io.spring.dependency-management' version '1.1.4'
}
// 之后 Spring 相关依赖自动不需要版本号

4.2 Gradle Version Catalog(Gradle 7.0+)

集中管理版本号,比 BOM 更灵活:

# gradle/libs.versions.toml
[versions]
spring-boot = "3.2.0"
guava = "32.1.3-jre"
junit = "5.10.0"

[libraries]
spring-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }

[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
// build.gradle.kts 中引用
dependencies {
    implementation(libs.spring.web)   // IDE 有自动补全
    implementation(libs.guava)
    testImplementation(libs.junit)
}

5. 实际开发中的选择建议

场景 建议
Spring Boot 新项目 Gradle Kotlin DSL + Version Catalog
维护已有 Maven 项目 继续用 Maven,没必要迁移
Android 项目 只能用 Gradle
公司统一规范 跟团队保持一致
个人学习/小项目 都行,推荐 Gradle 练手
需要高度自定义构建逻辑 Gradle
初始化项目 Spring Initializr,Maven 和 Gradle 都可以一键生成

6. 小结

主题 关键要点
构建工具本质 自动化依赖管理 + 编译 + 测试 + 打包 + 发布
Maven 核心 pom.xml + GAV 坐标 + 生命周期(clean → compile → test → package → install)
Maven 依赖管理 scope 控制范围、exclusion 排除冲突、dependencyManagement 统一版本
Maven 多模块 父 POM(packaging: pom)+ modules + dependencyManagement
Gradle 核心 build.gradle(Groovy/Kotlin DSL)+ 插件系统 + tasks
Gradle 依赖 implementation(不传递)vs api(传递),默认用 implementation
Gradle 优势 增量编译 + 构建缓存 + Daemon,速度远快于 Maven
Wrapper 始终用 ./gradlew 而不是全局 gradle,保证版本一致
版本管理 Maven 用 BOM,Gradle 用 Version Catalog(libs.versions.toml)

下一篇预告:Spring 核心思想——IoC 与 AOP 到底解决了什么问题


🎯 如果这篇文章对你有帮助,别忘了点赞、收藏、关注三连!关注我,让你在 Java 学习的道路上不迷路,持续为你带来成体系的 Java 干货~

更多推荐