当前位置: 首页 > news >正文

Maven 详解(中)

在 Maven 视图 中,展开你的项目

  • 右键点击任意一个依赖,会弹出一个菜单。
  • 选择 Show Dependency Hierarchy
  • 此时,VSCode 会打开一个新的标签页,以树状结构图形化地展示这个依赖的传递性依赖 (Transitive Dependencies)
    • 你可以清晰地看到哪些库是直接依赖,哪些是传递进来的。
    • 如果有版本冲突,通常也会有视觉提示(比如不同颜色或警告图标)。

依赖管理 (Dependency Management)

  • 直接依赖: 你在 pom.xml 的 <dependencies> 中显式声明的依赖。
  • 传递性依赖 (Transitive Dependencies): 当你的项目 A 依赖 B,而 B 又依赖 C 时,C 会自动成为 A 的依赖。Maven 会自动解析和下载整个依赖树。
  • 依赖范围 (Scope): 控制依赖在不同阶段(编译、测试、运行)的可用性和传递性。详见后文。
  • 依赖调解 (Dependency Mediation): 当依赖树中出现版本冲突时,Maven 会根据规则(路径最短优先、第一声明优先)自动选择一个版本。
  • 依赖排除 (Exclusion): 使用 <exclusions> 标签可以阻止某个传递性依赖被引入。
  • 可选依赖 (Optional): 使用 <optional>true</optional> 标记的依赖,不会被传递到依赖当前项目的其他项目。

依赖范围 (Scope) 深入详解

这是 Maven 中最容易混淆但也最重要的概念之一。它决定了依赖在项目生命周期中的可用性和传递性。

Scope编译 Classpath测试 Classpath运行 Classpath传递性说明
compile默认范围。核心依赖,参与所有阶段。
provided容器提供(如 Servlet API)。编译测试需要,运行时由 Tomcat 等提供。
runtime编译不需要,运行/测试需要(如 JDBC 驱动、Logback 实现)。
test仅测试用(如 JUnit, Mockito)。
system类似 provided,但 JAR 在本地路径 (<systemPath>)。不推荐
importN/AN/AN/AN/A仅用于 <dependencyManagement>,导入其他 POM 的依赖管理配置。

选择范围的建议:

  • 项目核心功能代码依赖 → compile
  • 编译时需要,但运行时由环境提供 → provided
  • 接口在 compile,实现类在运行时加载 → runtime
  • 只用于写测试代码 → test

dependencyManagement详解

<dependencyManagement> 并不是一个简单的“添加依赖”的地方。它的核心作用是集中声明依赖的版本号和配置,但不实际引入这些依赖

你可以把它想象成一个依赖版本的“声明清单”或“中央注册处”

  • 在 <dependencyManagement> 中声明:你告诉 Maven “如果项目(或其子模块)将来要使用 groupId:artifactId 这个库,那么请使用我这里指定的 version 和其他配置”。
  • 在 <dependencies> 中声明:你告诉 Maven “我的项目现在就需要这个库,请把它加入 classpath”。

只有当一个依赖既被 <dependencyManagement> 声明了版本,又在 <dependencies> 中被实际引用时,Maven 才会下载并使用它。


 主要用途与优势

  1. 统一版本管理 (Version Bumping)

    • 场景: 在一个多模块项目中,多个子模块都依赖 spring-corejackson-databindlombok 等库。如果没有 <dependencyManagement>,你需要在每个子模块的 pom.xml 中重复写上相同的 groupIdartifactIdversion
    • 问题: 当需要升级 jackson-databind 从 2.13.0 到 2.14.0 时,你必须手动修改每一个用到它的 pom.xml 文件,非常容易出错和遗漏。
    • 解决方案: 在父 POM 的 <dependencyManagement> 中声明所有公共依赖的版本。
      <!-- 父 pom.xml -->
      <dependencyManagement><dependencies><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version></dependency><!-- ... 其他公共依赖 --></dependencies>
      </dependencyManagement>
      子模块只需在 <dependencies> 中引用,无需指定版本:
      <!-- 子模块 pom.xml -->
      <dependencies><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><!-- 版本由父 POM 的 dependencyManagement 提供 --></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
      </dependencies>
    • 优势: 升级时,只需修改父 POM 中的一行代码,所有子模块自动继承新版本。
  2. 解决传递性依赖冲突 (Transitive Dependency Conflict Resolution)

    • 场景: 你的项目直接依赖 A 库 (v1.0),而 A 库依赖 C 库 (v1.5)。同时,你的项目直接依赖 B 库 (v2.0),而 B 库依赖 C 库 (v2.0)。这就导致了 C 库的版本冲突。
    • 问题: Maven 有默认的调解策略(路径最短优先),但这可能不是你想要的结果。
    • 解决方案: 在 <dependencyManagement> 中显式声明你希望使用的 C 库版本。
      <dependencyManagement><dependencies><dependency><groupId>com.example</groupId><artifactId>c-library</artifactId><version>1.8</version> <!-- 你期望的稳定版本 --></dependency></dependencies>
      </dependencyManagement>
      这样,无论 A 或 B 传递进来什么版本的 C 库,Maven 都会强制使用你在 <dependencyManagement> 中声明的 1.8 版本。
  3. 提供默认配置

    • 除了版本,你还可以在 <dependencyManagement> 中为依赖设置默认的 <scope><exclusions> 或 <optional> 等配置。这些配置会被实际引用该依赖的地方继承。

结合 Spring Boot:BOM (Bill of Materials) 模式

Spring Boot 将 <dependencyManagement> 的威力发挥到了极致,通过其官方提供的 BOM (物料清单) POM 来实现无缝的依赖管理。

什么是 BOM?

  • BOM 是一个特殊的 POM 文件(Artifact Type 为 pom),它本身不包含任何代码,只包含一个庞大的 <dependencyManagement> 块。
  • 对于 Spring Boot,这个 BOM 就是 spring-boot-dependencies
工作原理 (import Scope)

让我们回顾您之前提供的 pom.xml 片段:

<dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope> <!-- 关键! --></dependency></dependencies>
</dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 注意:这里没有 <version> 标签 --></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>
  1. <scope>import</scope>: 这是关键。import 范围告诉 Maven:“请将 spring-boot-dependencies-${version}.pom 这个文件中的 <dependencyManagement> 部分的内容,导入 (import) 到当前项目的 <dependencyManagement> 中”。
  2. spring-boot-dependencies 的内容: 这个 POM 文件内部有一个巨大的 <dependencyManagement> 块,其中包含了 Spring Boot 框架及其生态系统中几乎所有相关库的定义:
    • spring-framework-bom (Spring Framework 的 BOM)
    • hibernate-validator
    • jackson-bom (Jackson JSON 库的 BOM)
    • tomcat-embed-* (内嵌 Tomcat)
    • reactor-bom (Reactive 编程)
    • logback / log4j2
    • spring-data-bom
    • ... 以及数百个其他库。
  3. 效果:
    • 通过 import,你的项目就“继承”了 Spring Boot 团队精心挑选和测试过的一整套兼容的库版本。
    • 当你在 <dependencies> 中添加 spring-boot-starter-web 时,Maven 会解析它的传递性依赖(如 spring-webmvcjackson-databindtomcat-embed-core 等)。
    • 对于这些传递进来的依赖,Maven 会在 <dependencyManagement>(现在包含了 spring-boot-dependencies 的内容)中查找它们的版本号,并使用找到的版本,而不是依赖项自己声明的版本(这可以避免版本冲突)。
    • 结果:你只需要指定 spring-boot-starter-* 的版本(通过 ${spring-boot.version} 属性),就能确保整个技术栈的所有组件版本都是兼容且经过验证的。
为什么这是最佳实践?
  1. 免去版本烦恼: 开发者不再需要去网上查 spring-webmvc 应该用哪个版本,或者 jackson 和 spring 如何搭配。一切由 Spring Boot BOM 决定。
  2. 保证兼容性: Spring Boot 团队会确保 BOM 中的所有版本组合在一起能正常工作。
  3. 简化 pom.xml: 你的依赖列表变得非常简洁,只列出 Starter 和极少数特殊依赖。
  4. 一键升级: 升级 Spring Boot 版本时,只需修改 ${spring-boot.version} 属性,所有相关的库都会随之升级到兼容的新版本。

 总结

特性<dependencies><dependencyManagement>
是否引入依赖✅ 是,实际将依赖加入 classpath❌ 否,仅声明版本和配置
主要作用声明项目直接需要的依赖集中管理依赖版本,解决冲突
版本指定可以指定,也可以继承必须指定版本
与子模块关系不会被子模块继承会被子模块继承
在 Spring Boot 中的角色引入 Starter 和特定依赖通过 import 导入 spring-boot-dependencies BOM

简单来说:

  • 用 <dependencyManagement> + import 来决定 “用什么版本” (The Version Policy)。
  • 用 <dependencies> 来决定 “需要哪些功能” (The Feature List)。

通过这种方式,Maven 的 <dependencyManagement> 结合 Spring Boot 的 BOM 模式,极大地简化了复杂 Java 项目的依赖管理,让开发者能够更专注于业务开发。

http://www.dtcms.com/a/561865.html

相关文章:

  • 山西做网站流程步骤鉴定手表网站
  • 广州做淘宝的化妆品网站好个人网站学生作业
  • ReactNative如何处理跨平台差异和优化应用
  • 河北邯郸做wap网站微信网页版登录界面
  • 事件传递和响应者链
  • 07-神经元模型:介绍神经网络中神经元的结构和功能
  • 河南网站建设推广泰安招聘信息最新招聘2022
  • 第73题 矩阵置零
  • dw设计做网站案例使用免费的代码做网站
  • C++11新特性学习
  • 手机网站php源码网站建设课设心得
  • 网站年龄和域名年龄软件开发流程八个步骤模板
  • mybatis类型转换器
  • Vue项目中的Electron桌面应用开发实践指南
  • 如何运行asp.net网站wordpress怎么导入demo文件
  • focusPolicy/setFocusPolicy(FocusPolicy),styleSheet
  • 六.DockerFile解析及其应用部署
  • wp企业网站模板数据分析师事务所
  • AWS DMS 大规模数据库迁移:完全加载+持续复制最佳实践
  • 阿里巴巴六边形架构-从解耦到可测试的架构设计利器
  • 中国世界排名前500大学seo网上培训多少钱
  • 做网站做哪个行业好商城网站建设高端
  • 正规网站建设建设公司雅安建设局网站
  • 如何在Java中整合Redis?
  • 官方网站是什么意思免费链接生成器
  • 增加网站访客珠宝首饰商城网站建设
  • 网络通信的奥秘:TCP与UDP详解(三)
  • 理财网站开发最近中国新闻
  • 详解网络安全免杀对抗:攻防的猫鼠游戏
  • 【开题答辩全过程】以 高考志愿分析系统为例,包含答辩的问题和答案