【Maven从入门到实战教程】第六章 Maven依赖传递详解

依赖传递

大家要理解一个问题:Maven仓库中的所有jar,其实本质上都是一个Java项目,只是打成jar包放到Maven仓库中而已,既然是Java项目,那么这个项目可能也会用到一些第三方的jar包。

当我们引入某些jar包的时候,会把这些jar包依赖的jar包同样引入进来,这就是依赖传递。

    例如有个Commons-logging项目,项目Spring-core依赖Commons-logging,而项目user-service依赖Spring-core。那么我们可以说 user-service也依赖Commons-logging。也就是说,依赖的关系为:user-service—>Spring-core—>Commons-logging

    当我们执行项目user-service时,会自动把Spring-core、Commons-logging都下载导入到user-service项目的jar包文件夹中,这就是依赖的传递性。

dependency完整结构:

<dependencies>
    <dependency>
        <groupId>组织/父项目名称</groupId>
        <artifactId>项目名称</artifactId>
        <version>项目版本号</version>
        <type>依赖的类型,对应项目的packaging,默认是jar</type>
        <scope>依赖范围</scope>
        <systemPath>配合 scope=system 时使用</systemPath>
        <optional>标记是否为可选依赖</optional>
        <exclusions>
            <!-- 用来排除传递性依赖 -->
            <exclusion>
                <groupId>组织/父项目名称</groupId>
        		<artifactId>项目名称</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

    通过设置<optional>true</optional>,表示该依赖是可选的,不会被依赖传递。

举例验证:

    引入依赖spring-core。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>

结果如下:

    仔细观察,还发现此时还多了commons-logging:commons-logging:1.2,这就涉及到了“依赖”。

    当A jar包需要用到B jar包中的类时,我们就说A对B有依赖。当前工程会到本地仓库中根据坐标查找它所依赖的jar包。

    我们通过Maven仓库可以发现,spring-core编译的时候依赖了5个jar,但是最终依赖传递进来的只有一个,原因在于配置了optinal标签。

    注意:optional标签只能在自己的项目中设置不向下传递(如果我们把项目打成jar包,我们项目的中的某些依赖不向下传递),如果不想使用要别人项目传递进来的依赖,可以使用依赖传递的排除。

依赖传递的排除

    有时候为了确保程序正确,可以将有可能重复的间接依赖排除。

    依赖传递的排除的排除分为两种:
        1、通过配置文件排除依赖。
        2、Maven自动排除重复依赖。

 例如:C -> B -> A,假如现在不想执行C时把A下载进来,那么我们可以用<exclusions>标签

<dependencies>
    <dependency>
        <groupId>B</groupId>
        <artifactId>B</artifactId>
        <version>0.0.1</version>
        <exclusions>
            <exclusion>
                <!--被排除的依赖包坐标-->
                <groupId>A</groupId>
                <artifactId>A</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

    我们一般情况下,不要自己去写依赖排除,除非某些特殊情况。

    假如:junit依赖的hamcrest-core:1.3有版本问题,我们不想要junit依赖传递进来的hamcrest-core:1.3,那么我们就可以通过exclusion排除掉。

<!-- 引入junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

注意:要跟原来引出依赖的原包处于同一个<dependency></dependency>范围。

    依赖排除hamcrest-core之后,junit肯定就出现了问题,那么我们需要找一个没有版本问题的hamcrest-core再引入进来即可。

<!-- 引入hamcrest-core -->
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-core</artifactId>
    <version>2.2</version>
</dependency>

依赖排除的场景:

    1、项目A依赖项目B,但当项目A不是完全依赖项目B的时候,即项目A只用到了项目B的一部分功能,而正巧项目B这部分功能的实现,并不需要依赖于项目C,这个时候,项目A就应该排除对项目C的依赖。

    2、版本不匹配:依赖传递进来的jar包与实际用到的jar有版本不匹配问题,造成项目运行异常。

    3、封装公共模块:使用到某个jar中的API,如果此jar中有不需要的传递依赖,可以通过排除依赖传递。

依赖冲突与解决

    依赖冲突:一个项目A,通过不同依赖传递路径依赖于X,若在不同路径下传递过来的X版本不同,那么A应该导入哪个版本的X包呢?

    由于依赖的内容存在多个版本,如果出现某一个POM依赖多个版本时,则称之为依赖冲突。

    依赖冲突遵循两个原则:
        1、短路优先(依赖的内容,传递次数越小越优先)。
        2、先声明则优先(在POM.xml中,哪个依赖的内容声明dependency靠前,则优先。

举例验证:

    引入如下依赖:

<!-- spring核心包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>
<!-- spring beans包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>
<!-- spring环境包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>

    我们会发现,我们引入了spring-core,但是beans、context以及context里面的aop等都依赖传递了spring-core。那么项目中会引入多个jar吗? 

    答案是否定的。实际上Maven只引入了一个spring-core。

 冲突解决方案:

    1、如果依赖路径的长度不同,则采取最短路径原则:
        A—>B—>C—>D—>E—>X(version 0.0.2)
        A—>F—>X(version 0.0.1)
        则A依赖于X(version 0.0.1)。

    2、依赖路径长度相同情况下,则采取最先申明原则:
        A—>E—>X(version 0.0.1)
        A—>F—>X(version 0.0.2)
        则在项目A的<depencies></depencies>中,E、F哪个先声明则A依赖哪条路径的X。

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是波哩个波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值