欢迎光临
我们一直在努力

Java基础(15) | 构建工具:Maven vs Gradle,依赖管理与项目结构

📚 本系列系统梳理了 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 Central 或 mvnrepository.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

维度MavenGradle
配置文件 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 干货~

赞(0)
未经允许不得转载:171主机测评 » Java基础(15) | 构建工具:Maven vs Gradle,依赖管理与项目结构
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址