Maven中dependency(依赖)的scope(作用域)

一、作用域列举

Maven官网介绍:

There are 6 scopes available:

  • compile
    This is the default scope, used if none is specified. Compile dependencies are available in all classpaths of a project. Furthermore, those dependencies are propagated to dependent projects.
  • provided
    This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.
  • runtime
    This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
  • test
    This scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases. This scope is not transitive.
  • system
    This scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.
  • import
    This scope is only supported on a dependency of type pom in the <dependencyManagement> section. It indicates the dependency to be replaced with the effective list of dependencies in the specified POM's <dependencyManagement> section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.

先给出maven中的几种classpaths:

  • maven.compile.classpath         maven的编译路径
  • maven.runtime.classpath         maven的运行路径
  • maven.test.classpath               maven的测试路径
  • maven.plugin.classpath           maven的插件路径

简单翻译一下:

compile:作用域的默认值,如果没有特别声明,则默认使用compile。compile依赖会放在在一个项目的classpaths目录下。而且依赖关系可以在使用的项目之间传递(关于传递依赖,下面再讲)。---compile范围表示被依赖项目需要参与当前项目的编译,还有后续的测试,运行周期也参与其中,打包的时候通常需要包含进去需要注意

provided:provided在运行阶段,假定我们期望JDK或容器已经提供了这个jar包,除此之外,provided和compile非常相似。例如,在使用J2ee构建web应用程序时,因为web容器提供了这些类Servlet或J2EE API的一些类,所以我们需要将Servlet API和相关Java EE API的依赖范围设置为provided,provided依赖仅仅放在compile classpath和test classpath目录下,即仅仅在编译和测试时可用(在运行时有容器提供),且不具有传递依赖。

runtime:这个作用域意味着此依赖不需要参与项目编译,但是需要参与运行。runtime依赖会被放在test classpath和runtime classpath下,此项目依赖在后期的测试和运行周期需要其参与。与compile相比,跳过了编译而已。例如JDBC驱动,适用运行和测试阶段

test:这个作用域通常用在一个不是应用程序必须的依赖上,只是在测试代码的编译和执行阶段可用,而且不具备依赖传递性。例如 我们的JUnit4依赖

system:和provided相似,只不过你需要提供一个明确包含此依赖所需的jar包。这个依赖一直都是可用的而且在maven仓库是不存在的。从参与度来说,和provided相同。不过此依赖所需的jar包位置在本地系统中,需要systemPath的属性配合使用。

参考:

<dependencies>
    <!-- 在这里添加你的依赖 -->
    <dependency>
        <groupId>ldapjdk</groupId>  <!-- 库名称,也可以自定义 -->
        <artifactId>ldapjdk</artifactId>    <!--库名称,也可以自定义-->
        <version>1.0</version> <!--版本号-->
        <scope>system</scope> <!--作用域-->
        <systemPath>${basedir}\src\lib\ldapjdk.jar</systemPath> <!--项目根目录下的lib文件夹下-->
    </dependency> 
</dependencies>

import:这个作用域仅支持dependencyManagement块里面且类型为pom的依赖上,表明该依赖会被dependencyManagement块里指定的pom里所包含的依赖所取代,由于它们会被替代,所以使用import作用域的依赖实际上不会影响依赖的传递性。

例如:

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.gao.maven01</groupId>
                <artifactId>maven01</artifactId>
                <version>1.0-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

二、依赖传递介绍

 如果我们有三个maven项目,分别是A,B,C。项目A依赖项目B,项目B依赖项目C。此时项目A如果依赖项目C,那么此时依赖就具有传递性,在项目A中会把项目B和项目C的jar都加载到项目A的classpath中。

maven中各个作用域的依赖关系如下(引用maven官网的一张图):

Each of the scopes (except for import) affects transitive dependencies in different ways, as is demonstrated in the table below. If a dependency is set to the scope in the left column, transitive dependencies of that dependency with the scope across the top row will result in a dependency in the main project with the scope listed at the intersection. If no scope is listed, it means the dependency will be omitted.(每个作用域(import除外)都以不同的方式影响传递依赖,如下表所示。如果将依赖项设置为左列中的作用域,则该依赖项与顶行的作用域之间的传递依赖项将导致主项目中的依赖项与交集中列出的作用域之间的依赖项。如果没有列出范围,则意味着将忽略依赖项。)

A\Bcompileprovidedruntimetest
compilecompile(*)-runtime-
providedprovided-provided-
runtimeruntime-runtime-
testtest-test-

我们做个简单的解释,假设有项目A,B,C,上面表格左侧为项目A对项目B的依赖作用域,表格顶部为项目B对项目C的依赖作用域

1、项目A通过compile作用域引入项目B依赖,项目B通过compile作用域引入项目C依赖,则项目A会以compile作用域引入项目C依赖

2、项目A通过compile作用域引入项目B依赖,项目B通过provided作用域引入项目C依赖,则项目A和项目C之间依赖关系则丢失或不存在依赖关系

3、项目A通过compile作用域引入项目B依赖,项目B通过runtime作用域引入项目C依赖,则项目A会以runtime作用域依赖项目C

4、项目A通过compile作用域引入项目B依赖,项目B通过test作用域引入项目C依赖,则项目A和项目C之间不存来依赖关系

....以此类推

 

依赖关系的排除

如果我们项目A与项目C之间有传递依赖,但是我们项目A又不需要项目C,那该怎么办呢?没关系,我们此时可以通过依赖排除配置,让项目A不再引入项目C。

<!-- 依赖排除 -->
<dependencies>
    <dependency>
        <groupId>B</groupId>
        <artifactId>B</artifactId>
        <version>1.0</version>
        <!-- 配置要排除的依赖项 -->
         <exclusions>
            <exclusion>
              <groupId>C</groupId>
              <artifactId>C</artifactId>
              <version>2.0</version>
            </exclusion>
         </exclusions>
    </dependency>
</dependencies>

依赖冲突与冲突解决策略

假设我们有项目A,B,C,D和E,如果项目A依赖B,项目B依赖C,项目C依赖E,项目A,B,C,E之间都有依赖传递;同时项目A还依赖D,项目D也依赖E,项目A,D,E之间也有依赖传递。不过项目C依赖的E版本和项目D依赖的E版本不同,此时就会存在依赖冲突。也就是项目A不知道该使用哪个版本的项目E,当然针对这个问题,maven官方提供了两个解决策略。

1、最短距离优先策略:

       即依赖传递的距离最短的优先使用,以上面的例子,第一条依赖线路:A依赖B,B依赖C,C依赖E。第二条线路:A依赖D,D依赖E,所以第二条线路更短,也就是说会使用第二条线路所依赖的项目E来使用。

2、最先声明策略:

    如果两条线路长度相同,那么maven会以哪个先声明就使用哪个的策略来使用传递依赖。

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值