Maven 依赖排查

先从项目去看显而易见,假如我们有一个项目,父工程中包含一些子工程,如下:

我们想看一下samples-account中的依赖关系,那么我们可以打开 samples-account的pom文件,查看其maven依赖关系图。

我们可以看到此项目中maven的依赖关系如下。

 我们可以看到有很多红色的虚线和红色的实线,对于红色实线来说表示的是maven依赖冲突,对于红色虚线来说表示的是重复依赖或者是依赖被覆盖。

因为很乱,我们可以先按如下操作找到哪些有问题的依赖关系。

然后再找到我们要关注的依赖进行分析,如我们要看spring-context-support相关的依赖是否有冲突。我们可以左键单击选中这个节点,然后点击如下按钮:

 会自动关注到此依赖,如下图:

这样我们可以看到 spring-context-support 有俩版本,且samples-account直接引用过其1.0.5版本,dubbo-config-spring也引用过其1.0.5,dubbo则引用的是他的1.0.11版本(在这里由于就近原则,它的版本被改为1.0.5版本了)。我们从maven树中也能看到:

 那么jar包后面的omitted for conflict with 1.0.5是什么意思呢?

在 Maven 的依赖树中,当你看到“omitted for conflict with 1.0.5”这样的信息时,它意味着 Maven 在解析依赖时遇到了版本冲突,并决定省略(排除)了与指定版本(在此例中为 1.0.5)冲突的那个依赖。

具体来说,Maven 遵循了一套复杂的依赖解析算法,称为“最近者胜”(nearest wins)策略。当 Maven 检测到多个库都依赖了同一个库的不同版本时,它会根据依赖树中的层次结构和声明的顺序来决定使用哪个版本。在这个过程中,如果一个依赖被其他依赖以更高的版本或相同的版本引入,那么 Maven 可能会选择忽略(省略)那个较低版本的依赖。

例如,假设你有以下依赖结构:

  • 项目 A 依赖库 B 1.0.0
  • 库 B 1.0.0 依赖库 C 1.0.0
  • 项目 A 同时直接依赖库 C 1.0.5

在这种情况下,Maven 会选择库 C 的 1.0.5 版本,因为这是一个更直接的依赖,并且版本号更高。同时,它会将库 B 1.0.0 依赖的库 C 1.0.0 标记为“omitted for conflict with 1.0.5”,意味着它已经被省略了,以避免版本冲突。

如果你希望明确控制依赖的版本,你可以在项目的 pom.xml 文件中使用 <dependencyManagement> 部分来管理依赖的版本,或者使用 <exclusions> 标签来排除不需要的传递性依赖。

而omitted for duplicate又是什么意思呢?

 在Maven中,"omitted for duplicate"意味着存在多个具有相同groupIdartifactId的依赖项,但它们的版本不同或传递依赖路径不同,因此Maven或相关的构建工具(如IntelliJ IDEA)认为这些依赖是重复的。

具体来说,当Maven解析项目的依赖关系时,如果它发现两个或多个依赖项指向了同一个库(即相同的groupIdartifactId),但它们的版本不同,Maven就会尝试解决这种冲突。Maven的依赖调解机制会选择一个版本作为“赢家”,并将其他版本标记为“输家”。被标记为“输家”的依赖项在依赖树中可能就会被标记为"omitted for duplicate",表示它们因为与另一个相同但版本不同的依赖项冲突而被省略。

这种情况通常发生在项目的依赖关系比较复杂,特别是当项目直接或间接地通过传递依赖引入了同一个库的不同版本时。为了避免这种问题,可以在项目的pom.xml文件中使用<dependencyManagement>部分来管理依赖的版本,或者使用<exclusions>标签来排除不需要的传递性依赖。

 omitted for conflict with 和 omitted for duplicate有什么区别呢?

在Maven依赖管理的上下文中,omitted for conflict with 和 omitted for duplicate 这两个术语都与解决依赖冲突有关,但它们在描述冲突的原因和结果时略有不同。

  1. omitted for duplicate

    • 这通常表示在项目的依赖树中存在多个具有相同groupIdartifactId但可能不同版本的依赖项。Maven的依赖管理策略在处理这些依赖时,会选择一个版本(通常是最新版本,但也取决于依赖的声明顺序和范围),而将其他版本视为“重复的”并省略它们。
    • 当你在Maven的输出或日志中看到“omitted for duplicate”时,这通常意味着Maven已经自动解决了这个冲突,并选择了其中一个依赖项版本。
  2. omitted for conflict with

    • 这个术语更具体地指出了哪个依赖项与当前考虑的依赖项存在冲突。它表明,尽管两个依赖项在groupIdartifactId上匹配,但由于某种原因(例如,它们的版本不兼容或与其他依赖项存在冲突),Maven选择了省略其中一个。
    • “conflict with”后面通常会跟着与当前依赖项存在冲突的依赖项的详细信息,如版本号或groupId:artifactId组合。
    • 与“omitted for duplicate”不同,“omitted for conflict with”可能意味着需要手动干预来解决冲突,特别是当Maven的自动依赖管理策略不能提供一个满意的解决方案时。

总之,这两个术语都涉及Maven在构建项目时如何处理依赖冲突,但“omitted for duplicate”更侧重于描述多个相同依赖项的存在,而“omitted for conflict with”则更具体地指出了哪个依赖项与当前依赖项存在冲突。

对于这些冲突我们怎么解决呢?

假设你的项目(我们称之为project-A)依赖于两个库:library-Xlibrary-Y

  1. library-X 的版本1.0是你的项目直接依赖的。
  2. library-Y 是你的项目直接依赖的另一个库,但它又间接地依赖于library-X的版本2.0(作为它的传递性依赖)。

在Maven的依赖管理中,这会导致一个冲突,因为你的项目试图同时使用library-X的两个不同版本:1.0(直接依赖)和2.0(通过library-Y的传递性依赖)。

Maven的依赖树可能看起来像这样

project-A  
|-- library-X:1.0 (直接依赖)  
|-- library-Y:some-version  
    |-- library-X:2.0 (传递性依赖)

在这个例子中,Maven会尝试解决这个冲突。默认情况下,Maven会选择路径最短的依赖版本,也就是说,它会尽可能地使用直接声明的依赖版本。但是,这并不总是可行的,特别是当两个版本在API或行为上有不兼容的更改的时候。

当然还有项目依赖是这样冲突的:

1.projectA依赖LibraryB,LibraryB又依赖LibraryX1.0。

2.projectA依赖LibraryC,LibraryC又依赖LibraryX2.0。

ProjectA
|-- LibraryB
	|-- LibraryX1.0
|-- LibraryC
	|-- LibraryX2.0

要解决上述Maven依赖冲突问题,你可以通过在项目的pom.xml文件中配置<exclusions>标签来排除不需要的依赖版本。以下是一个示例配置,展示了如何排除LibraryB中的LibraryX 1.0版本依赖,以确保ProjectA只使用LibraryX的2.0版本(假设这是你想要保留的版本):

<project>  
    ...  
    <dependencies>  
        <!-- ProjectA依赖于LibraryB -->  
        <dependency>  
            <groupId>com.example</groupId>  
            <artifactId>LibraryB</artifactId>  
            <version>1.0</version>  
            <exclusions>  
                <!-- 排除LibraryB中的LibraryX 1.0版本 -->  
                <exclusion>  
                    <groupId>com.some.othergroup</groupId>  
                    <artifactId>LibraryX</artifactId>  
                </exclusion>  
            </exclusions>  
        </dependency>  
  
        <!-- ProjectA也依赖于LibraryC -->  
        <dependency>  
            <groupId>com.example</groupId>  
            <artifactId>LibraryC</artifactId>  
            <version>x.y.z</version>  
            <!-- 注意:这里不需要排除LibraryX,因为我们要保留的版本就是LibraryC所依赖的版本 -->  
        </dependency>  
  
        <!-- 直接指定LibraryX的2.0版本 -->  
        <dependency>  
            <groupId>com.some.othergroup</groupId>  
            <artifactId>LibraryX</artifactId>  
            <version>2.0</version>  
        </dependency>  
  
        <!-- 其他依赖... -->  
    </dependencies>  
    ...  
</project>

看着好像有那么点道理,然而,在上面的配置中,直接指定LibraryX的2.0版本可能会引发另一个问题:如果LibraryB确实需要LibraryX的1.0版本来正常工作,那么这种硬编码的依赖可能会导致LibraryB无法正常工作。

因此,更好的做法可能是确保LibraryBLibraryC维护者都更新他们的依赖项以使用兼容的版本,或者在项目的dependencyManagement部分统一指定一个兼容的版本(把问题提给项目的维护者吧)。

<project>  
    ...  
    <dependencyManagement>  
        <dependencies>  
            <!-- 统一指定LibraryX的版本为2.0 -->  
            <dependency>  
                <groupId>com.some.othergroup</groupId>  
                <artifactId>LibraryX</artifactId>  
                <version>2.0</version>  
            </dependency>  
            <!-- 其他依赖管理... -->  
        </dependencies>  
    </dependencyManagement>  
  
    <dependencies>  
        <!-- ProjectA依赖于LibraryB,但不需要显式排除LibraryX,因为dependencyManagement已经指定了版本 -->  
        <dependency>  
            <groupId>com.example</groupId>  
            <artifactId>LibraryB</artifactId>  
            <version>1.0</version>  
        </dependency>  
  
        <!-- ProjectA也依赖于LibraryC,同样不需要显式排除 -->  
        <dependency>  
            <groupId>com.example</groupId>  
            <artifactId>LibraryC</artifactId>  
            <version>x.y.z</version>  
        </dependency>  
  
        <!-- 通常情况下,不需要直接指定LibraryX的版本,因为dependencyManagement已经处理了 -->  
  
        <!-- 其他依赖... -->  
    </dependencies>  
    ...  
</project>

 在dependencyManagement部分指定的版本将作为项目的“首选”版本,Maven将尝试解析所有依赖以使用这个版本(除非在dependencies部分明确指定了不同的版本)。

具体依赖可参照这位博主的描述:maven依赖传递(直接、间接依赖)、解决依赖冲突(排除依赖、版本锁定dependencyManagement)_maven 间接依赖-CSDN博客

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 3、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于SSM+mysql框架的高并发和商品秒杀项目源码+项目说明.zip # seckill 一个整合SSM框架的高并发和商品秒杀项目,学习目前较流行的Java框架组合实现高并发秒杀API ## 项目的来源 项目的来源于国内IT公开课平台,质量没的说,很适合学习一些技术的基础,这个项目是由四个系列的课程组成的,流程分为几个流程,很基础地教你接触到一个相对有技术含量的项目 - Java高并发秒杀API之业务分析与DAO层 - Java高并发秒杀API之web层 - Java高并发秒杀API之Service层 - Java高并发秒杀API之高并发优化 其实这几个流程也就是开发的流程,首先从DAO层开始开发,从后往前开发,开始Coding吧! ## 项目环境的搭建 * **操作系统** : Ubuntu 17.04 * **IDE** :IntelliJ IDEA 2016.2.5 x64 用Eclipse也一样的,工具时靠人用的 * **JDK** : JDK1.8 建议使用JDK1.7以上版本,有许多语法糖用着挺舒服的 * **Web容器** : Tomcat 8.0 * **数据库** :Mysql-5.6.17-WinX64 实验性的项目用Mysql就足够啦 * **依赖管理工具** : Maven 管理jar包真的很方便 这里列出的环境不是必须的,你喜欢用什么就用什么,这里只是给出参考,不过不同的版本可能会引起各种不同的问题就需要我们自己去发现以及排查,在这里使用Maven的话时方便我们管理JAR包,我们不用跑去各种开源框架的官网去下载一个又一个的JAR包,配置好了Maven后添加pom文件坐标就会从中央仓库下载JAR包,如果哪天替换版本也很方便 --- ## 项目效果图 - 秒杀商品列表 ![效果图](/images/result_1.jpg) - 秒杀结束提示界面 ![效果图](/images/result_2.jpg) - 开始秒杀提示界面 ![效果图](/images/result_3.jpg) - 重复秒杀提示界面 ![效果图](/images/result_4.jpg) - 秒杀秒杀成功提示界面 ![效果图](/images/result_5.jpg) --- ## 项目的运行 ### 下载 ### 导入到IDE 这里因为是使用`IDEA`创建的项目,所以使用`IDEA`直接打开是很方便的,提前是你要配置好`maven`的相关配置,以及项目`JDK`版本, `JDK`版本必须在`1.8`以上,因为在项目使用了`Java8`的`LocalDateTime`以及`LocalDate`,所以低于这个版本编译会失败的 - IDEA 直接在主界面选择`Open`,然后找到项目所在路径,点击`pom.xml`打开就可以了 - Eclipse 这个项目是基于`IDEA`创建,我这里把项目转成了`Eclipse`的项目,如果你使用Eclipse的话也可以直接导入,只是步骤更繁琐一点,[Eclipse导入步骤](/note/EclipseImport.md) ## 项目编码 项目总结可能比较的长,**密集恐惧症**者请按小节进行阅读 - [(一)Java高并发秒杀API之业务分析与DAO层](/note/note1.md) - [(二)Java高并发秒杀API之Service层](/note/note2.md) - [(三)Java高并发秒杀API之web层](/note/note3.md) - [(四)Java高并发秒杀API之高并发优化](/note/note4.md) 这里按照上面几个流程走下去,你要有基本的Maven认识以及Java语法的一些概念,要不然可能不太理解 ### (一)Java高并发秒杀APi之业务分析与DAO层代码编写 #### 构建项目的基本骨架 * 首先我们要搭建出一个符合Maven约定的目录来,这里大致有两种方式,第一种: 1. 第一种使用命令行手动构建一个maven结构的目录,当然我基本不会这样构建 ``` mvn archetype:generate -DgroupId=com.suny.seckill -DartifactId=seckill -Dpackage=com.sun
Doe 发布 [V1.0.0] 前段时间排查某问题的时候,想要快速知道某些dubbo接口(三无)的响应结果,但不想启动项目(因为这些项目不是你负责的,不会部署而且超级笨重),也不想新建一个dubbo客户端项目(占地方),也不想开telnet客户端连接口(麻烦而且有限制)。所以扣了dubbo的netty模块源码,封装了个收发客户端集成一个工具,可以快速调试dubbo接口。源码地址:https://github.com/VIPJoey/doe 极简模式 普通模式 目录结构 mmc-dubbo-api 接口项目,主要用于测试。 mmc-dubbo-provider dubbo提供者项目,主要用于测试。 mmc-dubbo-doe 主项目,实现dubbo接口调试。 deploy 部署文档 功能特性 极简模式:通过dubbo提供的telnet协议收发数据。 普通模式:通过封装netty客户端收发数据。 用例模式:通过缓存数据,方便下一次操作,依赖普通模式。 增加依赖:通过调用maven命令,下载jar包和热加载到系统,主要用来分析接口方法参数,主要作用在普通模式。 依赖列表:通过分析pom文件,展示已经加载的jar包。 其它特性 springboot 整合 redis,支持spring el 表达式。 springboot 整合 thymeleaf。 springboot 整合 logback。 netty rpc 实现原理。 开发环境 jdk 1.8 maven 3.5.3 dubbo 2.6.1 lombok 1.16.20 idea 2018 windows 7 安装步骤 安装jdk 安装maven,并设置好环境变量,仓库目录。 进入mmc-dubbo-api目录,执行mvn clean install命令,省api的jar包。 进入mmc-dubbo-doe目录,执行mvn clean install 命令,在target目录生成dubbo-doe-1.0.0-RELEASE.jar 在F盘(可以任意盘)创建目录F:\app\doe 把dubbo-doe-1.0.0-RELEASE.jar拷贝到F:\app\doe 把deploy目录中的所有文件拷贝到F:\app\doe 如果您电脑安装了git bash,可以在bash窗口运行 ./deploy.sh start,否则如果没有安装git bash,只能打开cmd切换到F:\app\doe目录,然后执行java -jar dubbo-doe-1.0.0-RELEASE.jar --spring.profiles.active=prd 打开浏览器,访问地址:http://localhost:9876/doe/home/index 全剧终
当我们在使用Maven管理项目依赖时,有时候会遇到依赖爆红的情况。通常情况下,maven依赖爆红是因为以下几个原因: 1. 依赖版本不兼容:可能是项目中的其他依赖与该依赖版本不兼容,导致编译错误。解决方法是检查依赖之间的版本冲突,可以调整依赖的版本或者直接排除掉引起冲突的依赖。 2. 依赖未完全下载:有时候Maven仓库中的依赖包下载不完全或者损坏,会导致编译错误。解决方法是清除本地的Maven仓库缓存,然后重新下载依赖。 3. 依赖缺失:有时候Maven依赖没有正确声明或者没有在仓库中找到,会导致编译错误。解决方法是检查依赖声明是否正确,或者手动将依赖安装到本地Maven仓库。 4. Maven中央仓库连接问题:有时候Maven中央仓库的连接出现问题,导致依赖无法下载。解决方法是检查网络连接是否正常,或者更换其他可用的仓库源。 5. 缺少依赖范围声明:有时候依赖没有正确声明依赖范围,导致编译错误。解决方法是添加正确的依赖范围声明,确保依赖在编译、运行或测试等不同环境中的正确引用。 在解决依赖爆红问题时,我们可以通过查看Maven的编译日志和错误提示来定位问题,并逐个排查可能的原因。最重要的是了解项目使用依赖关系,合理管理依赖的版本和范围,以确保项目的稳定性和正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值