對晦澀的maven scope含義理解心得

對晦澀的maven scope含義理解心得

maven提供了5種scope(範圍)的定義,從字面上很難去明白其用處。首先所謂的【scope】是用來標註被dependency的包的作用域的。要搞清楚“什麼是scope”前,我們需要掌握兩個概念:第一,1個項目存在哪些方面受到scope影響(比如運行時,編譯時,測試編譯時,測試運行時…)。第二,就是有哪些scope的聲明(共有5個)。

小提示

被依賴的包,本質上就是一堆class字節碼源文件,這些文件主要在兩個階段被用到,運行階段,編譯階段。編譯器在編譯當前java文件時,會根據import聲明讀取被其他class字節碼文件,將類的全限定名(Fully Qualified Name)編織到當前字節碼中(可能會做一下校驗之類的)。

一、1個項目存在哪些方面受到scope影響

簡單的來說,scope影響的是JVM類加載器加載class字節碼的時間和空間。即,“什麼時候讀class字節碼,從哪裏讀取class字節碼。”
那麼,我們就可以從“時間”和“空間”的角度作劃分。

1. 從“時間”的角度劃分:

  • 運行時

就是main進程運行,類加載會加載所有相互依賴的字節碼文件,如果缺少某個被依賴的字節碼class文件,程序將會拋出ClassNotFound異常。

  • 編譯時

就是程序在compile階段就要提供字節碼class,用於聲明字節碼文件間的依賴關係,以及校驗字節碼類型是否合法之類的。

  • 測試編譯時

和編譯時一樣,只不過只對測試單元有效。

  • 測試運行時

和運行時一樣,只不過只對測試單元有效。

2. 從“空間”的角度劃分:

  • 編譯空間

    編譯時存放jar庫lib的目錄,即javac -Djava.ext.dirs=目錄,指定的目錄。在Intellj中則指定external libraries。在編譯java文件時會讀取編譯空間的類庫輔助完成編譯過程。

  • 容器空間

當編譯好的class文件需要運行時,就會去訪問容器的的類庫,比如tomcat的libs目錄。也就是說只要tomcat的Libs有提供類庫,那麼即使war沒有必要的類庫也可以正常運行。類似的,tomcat的Libs這樣的目錄我們稱之爲容器空間

  • 本地系統空間(比如JDK lib庫)

其實就是操作系統提供的lib目錄,可以是絕對路徑,也可以是環境變量中CLASSPATH中指定的路徑。這些我們都稱之爲 本地系統空間

  • Jar包內lib空間

Jar本質上就是一個壓縮包,Jar的壓縮包通常都有一個lib文件,這個文件存在依賴的其他Jar包。有了這個lib庫,就不需要系統額外的提供這些已有的jar包了。

二、有哪些scope的聲明(共有5個):

如下

  • compile (編譯範圍)

依賴範圍控制哪些依賴在哪些classpath 中可用,哪些依賴包含在一個應用中。讓我們詳細看一下每一種範圍:
compile (編譯範圍)
compile是默認的範圍;如果沒有提供一個範圍,那該依賴的範圍就是編譯範圍。編譯範圍依賴在所有的classpath 中可用,同時它們也會被打包。

  • provided (已提供範圍)

provided 依賴只有在當JDK 或者一個容器已提供該依賴之後才使用。例如, 如果你開發了一個web 應用,你可能在編譯 classpath 中需要可用的Servlet API 來編譯一個servlet,但是你不會想要在打包好的WAR 中包含這個Servlet API;這個Servlet API JAR 由你的應用服務器或者servlet 容器提供。已提供範圍的依賴在編譯classpath (不是運行時)可用。它們不是傳遞性的,也不會被打包。

  • runtime (運行時範圍)

runtime 依賴在運行和測試系統的時候需要,但在編譯的時候不需要。比如,你可能在編譯的時候不需要用到JDBC驅動(只需要JDBC API JAR),而只有在運行的時候才需要JDBC驅動實現。

  • test (測試範圍)

test範圍依賴 在一般的編譯和運行時都不需要,它們只有在測試編譯和測試運行階段可用。

  • system (系統範圍)

system範圍依賴與provided 類似,但是你必須顯式的提供一個對於本地系統中JAR 文件的路徑。這麼做是爲了允許基於本地對象編譯,而這些對象是系統類庫的一部分。這樣的構件應該是一直可用的,Maven 也不會在倉庫中去尋找它。如果你將一個依賴範圍設置成系統範圍,你必須同時提供一個 systemPath 元素。注意該範圍是不推薦使用的(你應該一直儘量去從公共或定製的 Maven 倉庫中引用依賴)。

總結:

總的來說,scope的定義既影響 編譯運行時機,也會影響包提供的空間位置。如果從字面上理解,有些混亂的,也很難記得住其中的規律。

幸運的是,我們可以依賴經驗,大部分情況下,都是compile(不聲明就是默認compile即可),當需要針對包提供的空間和時機進行針對性調整時,再去細心準確的對dependency進行配置也是可以的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章