Maven scope 依賴範圍詳解

Maven的生命週期存在編譯、測試、運行、打包這些過程,那麼顯然有些依賴只用於測試(test),比如 junit
有些依賴編譯用不到,只有運行的時候才能用到( runtime ),比如 mysql 驅動包在編譯期就用不到,而是在運行時用到的;
還有些依賴在編譯期要用到,而運行期不需要提供(provided),因爲有些容器已經提供了,比如 servlet-api 在 tomcat 中已經提供了,我們只需要的是編譯期提供而已。

總結說來,在POM 4中,<dependency>中還引入了<scope>,它主要管理依賴的部署。大致有 compile、provided、runtime、test、system 等幾個。

  1. compile:默認的scope,參與當前項目的編譯、測試、運行、打包等 全過程 參與。 (程序員寫的業務代碼)
  2. provided:編譯、測試階段存在,不會打入包中。(servlet-api.jarJDK
  3. runtime:編譯不需要,在運行、打包階段參與。(mysql.jar 驅動)
  4. test:測試需要,不會打入包中。(junit.jar
  5. system:不是從本地maven倉庫引入,而是在本地目錄的下的jar,與provided 相似 。一般不使用。 (oracle 驅動 ojdbc14.jar
<dependency>
    <groupId>groupId</groupId>
    <artifactId>artifactId</artifactId>
    <version>N</version>
    <scope>...</scope>
</dependency>

1.1、compile 模式 (默認,全過程參與)

默認就是 compile。

compile 需要參與當前項目的編譯、測試、運行、打包。

1.2、provided(編譯、測試階段存在,打包時排除)

provided 只存在編譯、運行、測試階段,打包是不用包括進去,打包階段做了 exclude 動作,因爲別的容器能提供對應的依賴。

應用場景:

定義了一個Servlet,此時需要servlet-api.jar 才能編譯成功,但是當你達成war 包時,你並不想將 servlet-api.jar 包進去,因爲Tomcat等容器會提供。此時用到 provided 。

provided 只在編譯、運行、測試階段,打包是不用包進去,打包階段做了排除。

provided 打包的時候可以不用包含進去,因爲別的容器(Web Container)會提供。

阿里開發規範文檔:如果依賴其它二方庫,儘量是 provided 引入,讓二方庫使用者去依賴具體版本號; 無 log 具體實現,只依賴日誌框架。

例如 : 添加 <scope>provided</scope> ,因爲provided表明該包只在編譯和測試的時候用,所以,當啓動tomcat 的時候,就不會衝突了。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>1.0-alpha-1</version>
    <scope>provided</scope>
</dependency>

1.3、runtime 模式(跳過編譯,運行和打包參與)

runtime 表示被依賴項目無需參與項目的編譯,不過後期的測試、運行和打包週期需要其參與。

與compile相比,runtime 跳過編譯而已。

比如,你可能在編譯的時候只需要 JDBC API JAR,而只有在運行的時候才需要 JDBC 驅動實現。

編譯時該包不參與,運行時參與。

1.4、test 模式(測試階段有效)

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

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <scope>test</scope>
</dependency>

1.5、system (依賴於本地目錄中,與provided 相似)

system 不是依賴於 maven倉庫、本地maven倉庫,而是從本地磁盤指定路徑下尋找,需要 systemPath 屬性。

與 provided 相似,不過不依賴maven倉庫,而是從本地文件系統讀取。

1)方式1、引入本地磁盤目錄下的jar包

<dependency>
    <!--自定義-->
    <groupId>com.im</groupId> 
    <!--自定義-->
    <artifactId>sdk</artifactId>   
    <!--自定義-->
    <version>1.0</version>
    <!--system,類似provided,需要顯式提供依賴的jar以後,Maven就不會在Repository中查找它-->
    <scope>system</scope>
    <!--項目根目錄下的lib文件夾下-->
    <systemPath>${basedir}/lib/sdk-1.0.jar</systemPath>
</dependency>

2)方式2、編譯階段指定外部 lib

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.1.2</version>
    
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>UTF-8</encoding>
        
        <compilerArguments>
            <!--指定外部lib-->
            <extdirs>lib</extdirs>
        </compilerArguments>        
    </configuration>
</plugin>

2、將外部 jar 導入本地 maven 倉庫

有一些收費的,或都其他途徑獲取的jar 在maven倉庫中不存在, 如果想通過maven使用時,可以先將jar導入到本地的maven倉庫中,如下:

mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc14  -Dversion=10.2.0.5.0 -Dpackaging=jar -Dfile=.\ojdbc14_10.2.0.5.0.jar

再引入jar包:

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc14</artifactId>
    <version>10.2.0.5.0</version>
</dependency>

3、maven預定義內置屬性

${basedir}          表示項目根目錄,即包含 pom.xml 文件的目錄;
${version}          表示項目版本;
${project.basedir}  同${basedir};
${project.baseUri}  表示項目文件地址;
${maven.build.timestamp}  表示項目構件開始時間;
${maven.build.timestamp.format}  表示屬性 ${maven.build.timestamp}  的展示格式,默認值爲 yyyyMMdd-HHmm ,可自定義其格式

4、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 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章