前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:说说 Maven 的依赖管理!

面试官:说说 Maven 的依赖管理!

作者头像
业余草
发布2021-03-03 10:51:19
9600
发布2021-03-03 10:51:19
举报
文章被收录于专栏:业余草业余草业余草

你知道的越多,不知道的就越多,业余的像一棵小草!

你来,我们一起精进!你不来,我和你的竞争对手一起精进!

编辑:业余草

jianshu.com/p/f6ca45865025

推荐:https://www.xttblog.com/?p=5151

最近在对一个老项目升级,SpringBoot 的版本从 1.x 升级到了 2.x 版本。其中遇到了不少包冲突,编译异常,启动异常等问题。本文结合一些简单的案例,用通俗易懂的语言给大家描述清楚 Maven 的依赖管理!

管理包依赖是 Maven 核心功能之一,下面通过如何引入 jar 包;如何解析 jar 包依赖;包冲突是如何产生;如何解决包冲突;依赖管理解决什么问题;什么是依赖范围;使用包依赖的最佳实践等 6 个问题来介绍。

如何引入 jar 包

在代码开发时,如果需要使用第三方 jar 包提供的类库,那么需要在 pom.xml 加入该 jar 包依赖。 例如:使用 zookeeper client

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
  <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.1</version>
  </dependency>
</dependencies>

Maven 如何解析 jar 包依赖——传递依赖

如上所述,在 pom.xml 中引入 zookeeper jar 包依赖,当 Maven 解析该依赖时,需要引入的 jar 包不仅仅只有 zookeeper,还会有 zookeeper 内部依赖的 jar 包,还会有 zookeeper 内部依赖的 jar 包依赖的 jar 包......,依赖关系不断传递,直至没有依赖。 例如:上述 pom.xml 引入 zookeeper 依赖,实际引入的 jar 包有:

zookeeper jar 依赖项

包冲突如何产生?

举个????:假设 A->B->C->D1, E->F->D2,D1,D2 分别为 D 的不同版本。 如果 pom.xml 文件中引入了 A 和 E 之后,按照 Maven 传递依赖原则,工程内需要引入的实际 Jar 包将会有:A B C D1 和 E F D2,因此 D1,D2 将会产生包冲突。

如何解决包冲突

Maven 解析 pom.xml 文件时,同一个 jar 包只会保留一个,这样有效的避免因引入两个 jar 包导致的工程运行不稳定性。

Maven 默认处理策略

  • 最短路径优先 Maven 面对 D1 和 D2 时,会默认选择最短路径的那个 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路径短 1。
  • 最先声明优先 如果路径一样的话,举个????:A->B->C1, E->F->C2 ,两个依赖路径长度都是 2,那么就选择最先声明。

移除依赖

如果我们不想通过 A->B->->D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉,这样也避免了包冲突。 举个????:将 zookeeper 的 jline 依赖排除

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
        </exclusion>
    </exclusions>
</dependency>

检测包冲突工具

mvn dependency:helpmvn dependency:analyzemvn dependency:treemvn dependency:tree -Dverbose
依赖管理解决什么问题

当同一个工程内有多个模块时,并且要求多个模块使用某个 jar 包的相同版本,为了方便统一版本号,升级版本号,需要提取出一个父亲模块来管理子模块共同依赖的 jar 包版本。 举个????:有两个模块 projectA, projectB,它们的依赖分别如下所示: projectA:

<project>  ...  <dependencies>    <dependency>      <groupId>group-a</groupId>      <artifactId>artifact-a</artifactId>      <version>1.0</version>      <exclusions>        <exclusion>          <groupId>group-c</groupId>          <artifactId>excluded-artifact</artifactId>        </exclusion>      </exclusions>    </dependency>    <dependency>      <groupId>group-a</groupId>      <artifactId>artifact-b</artifactId>      <version>1.0</version>      <type>bar</type>      <scope>runtime</scope>    </dependency>  </dependencies></project>
projectB:
<project>  ...  <dependencies>    <dependency>      <groupId>group-c</groupId>      <artifactId>artifact-b</artifactId>      <version>1.0</version>      <type>war</type>      <scope>runtime</scope>    </dependency>    <dependency>      <groupId>group-a</groupId>      <artifactId>artifact-b</artifactId>      <version>1.0</version>      <type>bar</type>      <scope>runtime</scope>    </dependency>  </dependencies></project>

projectA 和 projectB 共同依赖了 group-a/artifact-b/1.0,提取公共依赖,生成 parent, parent 依赖如下:

<project>  ...  <dependencyManagement>    <dependencies>      <dependency>        <groupId>group-a</groupId>        <artifactId>artifact-b</artifactId>        <version>1.0</version>        <type>bar</type>        <scope>runtime</scope>      </dependency>    </dependencies>  </dependencyManagement></project>
则 projectA 和 projectB 均不需要指定 group-a/artifact-b 的 version 信息。
未来升级 version 信息时,只需要在 parent 内部指定。


projectA:
<project>  ...  <dependencies>    <dependency>      <groupId>group-a</groupId>      <artifactId>artifact-a</artifactId>      <version>1.0</version>      <exclusions>        <exclusion>          <groupId>group-c</groupId>          <artifactId>excluded-artifact</artifactId>        </exclusion>      </exclusions>    </dependency>    <dependency>      <groupId>group-a</groupId>      <artifactId>artifact-b</artifactId>    </dependency>  </dependencies></project>
projectB:
<project>  ...  <dependencies>    <dependency>      <groupId>group-c</groupId>      <artifactId>artifact-b</artifactId>      <version>1.0</version>      <type>war</type>      <scope>runtime</scope>    </dependency>    <dependency>      <groupId>group-a</groupId>      <artifactId>artifact-b</artifactId>    </dependency>  </dependencies></project>
依赖范围

如果不显示执行 <scope> 属性时,默认 <scope>compile</scope>。 scope 有哪些属性:compile, provided, runtime, test, system 等。 详细参考:依赖范围

最佳实践

  • 项目中源代码使用的 jar 包一定在 pom.xml 中显示引用。
  • 经常 check 一下包冲突,检查是否需要处理。
  • 当使用多个模块时,parent 一定要使用包管理模块来规范 Jar 包版本,而不是包依赖模块直接引入依赖。dependencyManagement vs dependencies
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-02-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 你知道的越多,不知道的就越多,业余的像一棵小草!
  • 编辑:业余草
  • jianshu.com/p/f6ca45865025
  • 推荐:https://www.xttblog.com/?p=5151
  • 如何引入 jar 包
  • Maven 如何解析 jar 包依赖——传递依赖
  • 包冲突如何产生?
  • 如何解决包冲突
    • Maven 默认处理策略
      • 移除依赖
      • 最佳实践
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档