前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文理解Maven如何解决依赖冲突与循环依赖

一文理解Maven如何解决依赖冲突与循环依赖

作者头像
全菜工程师小辉
发布2021-07-23 16:47:35
5.3K0
发布2021-07-23 16:47:35
举报

Maven中依赖冲突与循环依赖是开发过程中比较令人头疼的问题。

依赖冲突

首先介绍下Maven中依赖管理的策略。

依赖传递:如果A依赖B,B依赖C,那么引入A,意味着B和C都会被引入。

最近依赖策略:如果一个项目依赖相同的groupId、artifactId的多个版本,那么在依赖树(mvn dependency:tree)中离项目最近的那个版本将会被使用。

具体如下:

  1. 从当前项目出发,对于同一依赖,优先使用路径最短的那个,无论版本号高低。

2. 同级别的引用,若pom.xml直接引用了两个不同版本的同一个依赖,maven会使用后解析的依赖版本。

3. 若两个不同版本的同一依赖都不是直接在pom.xml下引入,而是间接引入。那么哪个依赖先被引用,就使用哪个版本。

解决依赖冲突

  1. 使用<dependencyManagement>用于子模块的版本一致性,可以在parent工程里统一管理所有工程的依赖版本。
  2. 使用<exclusions>去除多余的依赖,IDEA提供相关可视化的操作。
  3. 根据最近依赖策略使用<dependency>,直接在当前项目中指定依赖版本。

实际开发中依赖冲突的问题复杂多变,需要具体问题具体处理。除了上面三种解决方法,工程结构调整也是一个可能的选择。

循环依赖

正常情况下,循环依赖是很少见的,当很多个项目互相引用的时候,就可能出现循环依赖,一般根据错误信息就能解决循环依赖。

解决循环依赖

  1. 使用build-helper-maven-plugin插件可以解决无法构建的问题,但是只是一个规避措施,工程的依赖关系依然是混乱的。

比如A依赖B,B依赖C,C依赖A的情况。这个插件提供了一种规避措施,即临时地将工程A、B、C合并成一个中间工程,编译出临时的模块D。然后A、B、C再分别依赖临时模块D进行编译。

2. 通过重构,从根本上消除循环依赖。

3. 如果循环依赖中确实有多余的部分,可以使用<exclusions>去除多余的依赖。(IDEA可以通过图像化界面定位循环依赖)

补充

Maven的基础知识

  • groupId是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。

一般分为多个段,第一段为域,第二段为公司名称…域又分为org、com、cn等等许多,其中org为非营利组织,com为商业组织。

  • artifactId是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。

一个Maven项目,同一个groupId同一个artifactId下,只会加载一个version。

代码语言:javascript
复制
例如:
<dependency>
    <groupId>org.xiaohui</groupId>
    <artifactId>maven-desc</artifactId>
    <version>5.3.8</version>
</dependency>

依照这个设置,包结构最好是org.xiaohui.maven-desc。如果有个StudentDao,那全路径就是org.xiaohui.maven-desc.dao.StudentDao

Maven仓库有哪些

  1. 本地仓库 本地仓库指的是${user_home}/.m2/repository/,Maven默认会先从本地仓库内寻找所需Jar包。如果本地仓库不存在,Maven才会向远程仓库请求下载,同时缓存到本地仓库。
  2. 远程仓库分为中央仓库,私服和其他公共库。
    1. 中央仓库 Maven自带的远程仓库,不需要特殊配置。如果私服上也不存在Maven所需 Jar包,那么就去中央仓库上下载Jar包,同时缓存在私服和本地仓库。
    2. 私服 为了节省资源,一般是局域网内设置的私有服务器,当本地仓库内不存在Maven 所需Jar包时,会先去私服上下载Jar包。(内网速度要大于从外部仓库拉取镜像的速度)
    3. 其他公共库 为了解决中央仓库网络对于国内不稳定的问题,常用如阿里云镜像仓库。

Maven的打包命令

IDEA中的Maven插件功能如图:

这个图表示Maven逐次递进(执行下面的命令就会包含上面的)的打包命令。

常用的打包命令:

  1. clean:清理本地工程Jar包。
  2. package:本地工程打成Jar包。会执行clean和compile。
  3. install:将本地工程Jar上传到本地仓库。
  4. deploy:上传到远程仓库。

Maven的依赖范围(scope)

代码有编译、测试、运行的过程,显然有些依赖只用于测试,比如Junit;有些依赖编译用不到,只有运行的时候才能用到,比如MySQL的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,只需要的是编译期提供而已。

所以Maven支持指定依赖的scope:

  1. compile:默认的scope,运行期有效,需要打入包中。
  2. provided:编译期有效,运行期不需要提供,不会打入包中。
  3. runtime:编译不需要,在运行期有效,需要导入包中。(接口与实现分离)
  4. test:测试需要,不会打入包中。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全菜工程师小辉 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 依赖冲突
    • 解决依赖冲突
    • 循环依赖
      • 解决循环依赖
      • 补充
        • Maven的基础知识
          • Maven仓库有哪些
            • Maven的打包命令
              • Maven的依赖范围(scope)
              相关产品与服务
              云数据库 MySQL
              腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档