Maven的生命週期存在編譯、測試、運行、打包這些過程,那麼顯然有些依賴只用於測試(test),比如 junit
;
有些依賴編譯用不到,只有運行的時候才能用到( runtime ),比如 mysql 驅動包在編譯期就用不到,而是在運行時用到的;
還有些依賴在編譯期要用到,而運行期不需要提供(provided),因爲有些容器已經提供了,比如 servlet-api
在 tomcat 中已經提供了,我們只需要的是編譯期提供而已。
總結說來,在POM 4中,<dependency>
中還引入了<scope>
,它主要管理依賴的部署。大致有 compile、provided、runtime、test、system
等幾個。
- compile:默認的scope,參與當前項目的編譯、測試、運行、打包等 全過程 參與。 (程序員寫的業務代碼)
- provided:編譯、測試階段存在,不會打入包中。(
servlet-api.jar
、JDK
) - runtime:編譯不需要,在運行、打包階段參與。(
mysql.jar
驅動) - test:測試需要,不會打入包中。(
junit.jar
) - 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