1. 程式人生 > >Maven 依賴中 scope 詳解

Maven 依賴中 scope 詳解

  • Maven 的哲學思想是,約定優於配置(Convention Over Configuration),Maven 依賴中 scope 的預設值是compile
  • Scope 指定了依賴(第三方jar包)的 作用範圍
  • 作用範圍包括,所在專案的測試、編譯、執行、打包等生命週期
  • 其中,編譯和執行還分為
    • 測試程式碼的編譯和執行
    • 非測試程式碼的編譯和執行

scope 分類

  • test 測試範圍
    • 測試範圍的依賴(第三方jar包),針對測試相關程式碼的編譯和執行,在通常程式碼的編譯和執行時都不需要,只有在有關測試的程式碼編譯和執行測試程式碼階段
      可用
    • 案例說明
      • 環境 IJ maven web project
      • 前提:需知facade slf4j 只有在classpath 中發現底層日誌實現framework時才起作用
        pom.xml
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <!--此處test,表明 junit jar包只能出現在 test 環境下的classpath,
            即 只能在標記為 “TestSources Root的 資料夾下”被呼叫, 而在“標記為Sources Root 的資料夾下”找不到其中的類-->
            <scope>test</scope> 
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
            <!--此處test 是關鍵,表明底層日誌實現框架-也即該依賴在test 程式碼編譯、執行時才起作用-->
            <scope>test</scope> 
        </dependency>

    </dependencies>

測試程式碼

  • 測試方法之一,即是上面pom註釋,junit 類呼叫只能在TestSources Root 目錄下起作用
  • 測試方法之二

Sources Root 目錄下

public class LogDemo {
    Logger logger = LoggerFactory.getLogger(LogDemoTest.class);
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(LogDemo.class);
        //不能找到底層日誌使系統,因為 該依賴 為 test 範圍
        logger.info("log");
    }
}

輸出:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

TestSources Root 目錄下

public class LogDemoTest {
    Logger logger = LoggerFactory.getLogger(LogDemoTest.class);
    @Test
    public void test() {
        //能找到底層日誌實現系統
        logger.info("junit test"); 
    }
}

輸出:
[main] INFO log.learn.LogDemoTest - junit test
  • compile 編譯範圍
    • 依賴預設範圍,該依賴需要參與當前專案的編譯、測試、執行、打包
    • 什麼叫參與當前專案的編譯???
  • runtime 執行時範圍
    • 表示依賴無需參與當前專案的編譯,但是後期的執行和測試需要參與,不參與編譯能執行成功嗎??
    • 與 compile 相比,跳過編譯而已
    • 比如,你可能在編譯的時候需要 JDBC API JAR,只有在 執行時才需要 JDBC
    • 貌似是編譯時該包不參與,執行時參與
  • provided 表明該依賴已經提供,故只在未提供時才被使用
    • 應用場景是你定義了一個Servlet,此刻得需要Servlet-api.jar 才能編譯成功,但是當你達成war 包時,你並不想將 Servlet-api.jar 包進去,因為Tomcat等容器會提供
    • 跟compile 類似,說明JDK、容器或使用者會提供這個依賴,如Servlet.jar
    • 這個依賴只作用在** 編譯和測試,該依賴會由系統元件提供,不需手動新增,只存在編譯、執行、測試階段,打包是不用包進去,打包階段做了exclude**動作
    • 沒有傳遞性
  • system
    • 被依賴項不會從maven倉庫下載,而是從本地系統指定路徑下尋找,需要 systemPath 屬性

scope 的傳遞依賴

  • A -> B -> C, 當前專案 A,A依賴於B,B依賴於C,知道B在 A中的scope,怎麼知道 C在 A 中的 scope
    • 即,A需不需要 C的問題,本質由 C在B中的scope決定
    • 當 C 在 B 中的scope 是test 或 provided 時,C 直接被丟棄A不依賴C
    • 否則 A 依賴 C,C的scope 繼承與B 的scope