
🌈 个人主页: Hygge_Code
🔥 热门专栏:从0开始学习Java | Linux学习| 计算机网络
💫 个人格言: "既然选择了远方,便不顾风雨兼程"

文章目录
- 依赖管理
-
- 依赖传递🤔
- 依赖冲突问题解决🐦🔥
-
- [1. 间接依赖 - 声明优先](#1. 间接依赖 - 声明优先)
- [2. 直接依赖高于间接依赖](#2. 直接依赖高于间接依赖)
- [3. 排除依赖原则](#3. 排除依赖原则)
- [4. 版本锁定](#4. 版本锁定)
- 依赖范围(使用scope指定范围)🥝
-
- [常用依赖范围 📖](#常用依赖范围 📖)
-
- [1. compile(默认范围)🍋🟩](#1. compile(默认范围)🍋🟩)
- [2. test 🍋🟩](#2. test 🍋🟩)
- [3. runtime🍋🟩](#3. runtime🍋🟩)
- [4. provided🍋🟩](#4. provided🍋🟩)
- 声明周期
-
- Maven对项目周期的构建分为3个🧾
-
- [1. clean生命周期](#1. clean生命周期)
- [2. default生命周期](#2. default生命周期)
- [3. site生命周期](#3. site生命周期)
- 插件
依赖管理
依赖指的是当前项目运行所需要的jar包,一个项目可以有很多个依赖。
依赖传递🤔
依赖具有传递性:
- 直接依赖:在当前项目中,通过依赖配置建立的依赖关系
- 间接依赖:被依赖的资源,如果还依赖其他资源,那么当前项目间接依赖其他资源

示例:
xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
编写了上面的依赖代码后,产生了下图的依赖文件

依赖冲突问题解决🐦🔥
依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突
示例代码:
xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
通过查看依赖,我们发现spring-aop和spring-context都依赖了一个叫spring-core的依赖。此时spring-core的版本有两个,这就产生了依赖冲突。

可以看出,以上产生的依赖冲突由maven自行解决了。
下面我们来看依赖冲突是如何解决的:
1. 间接依赖 - 声明优先
**规则:**谁先定义的就用谁的传递依赖(间接依赖),即在pom.xml文件自上而下,先声明的jar坐标,就先引用该jar的传递依赖。
原示例代码引入的两个依赖包中均包含spring-core 和 spring-beans(都属于间接依赖),而由于直接依赖sping - aop先被声明使用,所以spring - aop中的间接依赖优先于后面声明使用的 spring-beans中的间接依赖。
因此我们如果要使用5.2.0版本的spring core包,我们可以改成如下声明:
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>

2. 直接依赖高于间接依赖
**规则:**直接依赖高于间接依赖
这里还是基于原示例代码讲解:
最先声明使用的spring-context依赖里含有spring-aop依赖(间接依赖),但使用的却是下面的spring-aop,这是因为下面声明定义的spring-aop依赖为直接依赖,而直接依赖的优先级高于间接依赖。

3. 排除依赖原则
**规则:**在不影响项目运行的情况下,如果依赖冲突,可以把被冲突的依赖排除掉,注意排除的依赖不需要添加依赖的版本号 【使用exclusion】
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
添加了exclusion部分后,去掉了spring-context中包含的依赖spring-core
4. 版本锁定
**规则:**使用 dependencyManagement 进行版本锁定
dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,如果我们项目中只想使用spring core 5.2.0的包,pom.xml可以改为如下:
xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>

可以看到,spring-core的依赖从原示例代码版本的5.2.7变为了5.2.0
依赖范围(使用scope指定范围)🥝
Maven 的依赖范围(Dependency Scope) 是用来控制依赖在项目构建的不同阶段(编译、测试、运行)是否生效,以及依赖是否会被传递的核心机制。它解决了"不同环境需要不同依赖"的问题(比如测试依赖不需要打包到最终产物中),同时也能避免依赖冲突和冗余。
Maven 构建生命周期主要分为 3 个核心阶段:
- 编译(compile) :项目主代码(
src/main/java)的编译 - 测试(test) :测试代码(
src/test/java)的编译和运行 - 运行(runtime):项目运行时(如打包后的 jar/war 运行)
依赖范围本质上是定义:该依赖在哪些阶段可见,是否会被传递给下游项目,是否会被打包到最终产物中。
常用依赖范围 📖
以下是 Maven 4种常用的依赖范围:
| 范围 | 编译主代码 | 测试代码 | 运行时 | 传递性 | 打包到产物 | 典型场景 |
|---|---|---|---|---|---|---|
compile |
✅ | ✅ | ✅ | ✅ | ✅ | 核心业务依赖(如 Spring Core) |
test |
❌ | ✅ | ❌ | ❌ | ❌ | 测试框架(JUnit、TestNG) |
runtime |
❌ | ✅ | ✅ | ✅ | ✅ | 运行时依赖(如 JDBC 驱动) |
provided |
✅ | ✅ | ❌ | ❌ | ❌ | 容器提供的依赖(如 Servlet API) |
1. compile(默认范围)🍋🟩
-
含义:默认的依赖范围,适用于所有构建阶段(编译、测试、运行)。
-
特点 :
- 主代码和测试代码都能引用该依赖;
- 依赖会被传递(下游项目引入当前项目时,该依赖会自动引入);
- 最终会被打包到 jar/war 等产物中。
-
示例 :
xml<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.1.0</version> <!-- 省略 scope,默认 compile --> </dependency>
2. test 🍋🟩
-
含义:仅用于测试阶段(测试代码的编译和运行),主代码不可见。
-
特点 :
- 主代码(
src/main)无法引用该依赖; - 不传递(下游项目不会继承该依赖);
- 不会被打包到最终产物中。
- 主代码(
-
示例 :
xml<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> <!-- 仅测试用 --> </dependency>
3. runtime🍋🟩
-
含义:编译主代码时不需要,但运行时(包括测试运行)需要。
-
特点 :
- 主代码编译时无法引用(比如 JDBC 驱动,编译时只需要接口,运行时需要实现);
- 测试代码和运行时可见;
- 会被传递,且打包到产物中。
-
示例 :
xml<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <scope>runtime</scope> <!-- 仅运行时需要 --> </dependency>
4. provided🍋🟩
-
含义:编译和测试阶段需要,但运行时由容器/环境提供(无需打包)。
-
应用场景 :
- Web 项目中的 Servlet API(Tomcat 等容器已自带);
-
特点 :
- 编译/测试可见,运行时不可见;
- 不传递,不打包(避免和容器依赖冲突)。
-
示例 :
xml<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> <!-- 容器提供 --> </dependency>
声明周期
Maven对项目周期的构建分为3个🧾
clean: 清理工作阶段
default:核心工作阶段。比如编译、测试、打包、部署等
site: 产生报告,发布站点等

1. clean生命周期
- pre-clean 执行一些需要在clean之前完成的工作
- clean 移除所有上一次构建生成的文件
- post-clean 执行一些需要在clean之后立刻完成的工作
2. default生命周期

3. site生命周期
- pre-site 执行一些需要在生成站点文档之前完成的工作
- site 生成项目的站点文档
- post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
- site-deploy 将生成的站点文档部署到特定的服务器
插件
**介绍:**插件与生命周期内的阶段绑定,在执行到对应生命周期时,执行对应的插件功能,默认maven在各个生命周期阶段上绑定有预设功能。
我们也可以通过插件可以自定义其他功能,下面我们写一个自定义插件---在生成测试代码的时候,给主程序源代码打包、同时给测试源代码打包:
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<!-- 自定义插件的执行逻辑 -->
<executions>
<execution>
<goals>
<!-- 生成「主源码包」(src/main/java 下的源码) -->
<goal>jar</goal>
<!-- 生成「测试源码包」(src/test/java 下的源码) -->
<goal>test-jar</goal>
</goals>
<!-- 绑定执行时机:到 generate-test-resources 阶段 -->
<phase>generate-test-resources</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
测试结果如下:

如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!
