1. 程式人生 > >Maven中dependency(依賴)的scope(作用域)

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\B compile provided runtime test
compile compile(*) - runtime -
provided provided - provided -
runtime runtime - runtime -
test test - 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會以哪個先宣告就使用哪個的策略來使用傳遞依賴。