我尽全力挽留你的离开,可只能放开对你的依赖,你带走世界的绚丽多彩,留下了代表空寂的灰白,我不知道怎么把对你的依赖抛开,但明白只有这样才不会令我悲哀,我重新描绘色彩,是一个没有你的未来。

Maven依赖图解,maven图解

传递性依赖和依赖范围

Maven的依赖是具有传递性的,比如A->B,B->C,那么A间接的依赖于C,这就是依赖的传递性,其中A对于B是第一直接依赖,B对于C是第二直接依赖,C为A的传递性依赖。

在平时的开发中,如果我们的项目依赖了spring-core,依赖范围是compile,spring-core又依赖了commons-logging,依赖范围也是compile,那么我们的项目对于commons-logging这一传递性依赖的范围也就是compile。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围。我们通过下面这个表格来说明,其中最左边一栏是第一直接依赖,最上面那一栏为第二直接依赖。中间交叉的是传递性依赖范围。

 

Compile

Test

Provided

Runtime

Compile

Compile

 

 

Runtime

Test

Test

 

 

Test

Provided

Provided

 

Provided

Provided

Runtime

Runtime

 

 

Runtime

例如:第一直接依赖范围是Test,第二直接依赖范围是Compile,那么传递性依赖的范围就是Test,大家可以根据这个表去判断。

仔细观察一下表格,我们可以发现这样的规律:

  • 当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
  • 当第二直接依赖的范围是test的时候,依赖不会得以传递;
  • 当第二直接依赖的范围是provided的时候,只传递第一直接依赖的范围也为provided的依赖,且传递性依赖的范围同样为provided;
  • 当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile例外,此时传递性依赖的范围为runtime。

传递性依赖和依赖范围
Maven的依赖是具有传递性的,比如A-B,B-C,那么A间接的依赖于C,这就是依赖的传递性,其中…

  • maven项目中需要使用到其它依赖时,则需要在pom.xml中配置<dependency>元素也就是依赖声明,这样在编写项目时就可以使用依赖了,并且会在打包时自动将依赖的jar包打包到项目中。

版权作品,未经《短文学》书面授权,严禁转载,违者将被追究法律责任。

1.依赖声明

  • 一个依赖声明可以包含如下的一些元素。

<project>
  <dependencies>
    ...
    <dependency>
      <groupId>...</groupId>
      <artifactId>...</artifactId>
      <version>...</version>
      <type>...</type>
      <scope>...</scope>
       <optional>...</optional>
        <exclusions>
           <exclusion>
            ...
            </exclusion>
         </exclusions>
    </dependency>
     ...
  </dependencies>
</project>
  • gourpId、artifactId、version:依赖的基本坐标,必须填写,maven根据这3个信息找到需要的依赖。

  • type:依赖的类型,大部分情况是jar,默认是jar。

  • scope :依赖的范围,后面详解。

  • optional: 标记依赖是否可选,值为true或false,默认为false,
    如果为可选依赖,则依赖不具有传递性。即B->X(可选依赖),A->B。此时A的依赖中不包含X。

  • exclusions:用来排除传递性依赖。

大部分依赖声明只包含基本坐标,然而在一些特殊情况下,其他元素至关重要。

2.依赖范围

  • classpath:用于指定.class文件存放的位置,类加载器会从该路径中加载所需的.class文件到内存中。详细看类加载器

  • maven在编译项目主代码时需要使用一套classpath
    ,比如在使用spring框架的项目中,项目主代码需要用到spring-core依赖,scope为compile。该文件以依赖的方法被引入到classpath中。

  • maven在编译和执行测试代码时会使用另一套classpath。比如JUint,scope为test,该文件以依赖的方式引入到测试使用的calsspath中。

  • maven实际运行项目时又会使用一套classpath,上面的spring-core需要在该classpath中,而JUnit不需要。

maven依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系。
编译classpath:编译主代码有效
测试classpath:编译、运行测试代码有效
运行classpath:项目运行时有效

  • maven的依赖范围:

  • compile
    编译依赖范围。(默认方式),有效范围:编译classpath+测试classpath+运行classpath
    比如:spring-core,在编译测试运行阶段都需要使用。

  • test
    测试依赖范围。有效范围:测试classpath
    比如:JUnit,只在测试时使用,在编译主代码和运行时不需要此依赖。

  • provided
    已提供依赖范围。有效范围:编译classpath+测试classpath。
    比如:servlet-api。编译和测试项目时候需要该依赖,但在运行项目时,由于web容器已经提供,就不需要maven重复引入一遍了。

  • runtime
    运行时依赖范围。有效范围:测试classpath+运行classpath
    比如:JDBC驱动实现(mysql-connector-java),项目主代码编译时只需要JDK提供的JDBC接口,只有在执行测试或者运行项目时候才需要具体的JDBC驱动。

  • system
    系统依赖范围。有效范围:编译classpath+测试classpath
    使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径,因为此类依赖不是通过maven仓库解析的,而且往往与本地及其系统绑定,可能造成构建的不可移植,慎用。systemPath元素可以引用环境变量。
    比如:

<dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>
      <systemPath>${JAVA_HOME}/lib/rt.jar</systemPath>
    </dependency>

3.依赖传递

  • 一个maven项目A依赖spring-core依赖范围为compile,因为spring-core又依赖
    commons-logging依赖范围为compile,那么commons-logging就会成为A的compile范围依赖,commons-logging就是A的一个传递性依赖。

假设A依赖与B,B依赖与C,则A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围。如下表,最左边是第一直接依赖范围,上面是第二直接依赖范围,中间交叉单元格表示传递性依赖范围。

第一直接依赖第二直接依赖 compile test provided runtime
compile compile runtime
test test test
provided provided provided provided
runtime runtime runtime
  • 规律:
    • 第二直接依赖范围是compile时,传递依赖的范围与第一直接依赖范围一致。
    • 第二直接依赖范围是test时,依赖不会传递
    • 第二直接依赖范围是provided时,只传递第一直接依赖为provided的依赖。
    • 第二直接依赖范围是runtime时,传递依赖的范围与第一直接依赖范围一致,但是compile例外,此时传递依赖范围为runtime。

发表评论

电子邮件地址不会被公开。 必填项已用*标注