maven快速入門第六講——依賴的作用範圍

引子

在前一講中,使用maven裏面帶有的tomcat7插件運行maven項目成功後,在Google Chrome瀏覽器訪問HelloServlet時,發現報如下錯誤。
在這裏插入圖片描述
爲什麼會報錯呢?這是因爲我們本地tomcat服務器的lib目錄中已經存在servlet-api.jar和jsp-api.jar這倆jar包了。
在這裏插入圖片描述
而我們的maven項目又再次引入了這倆jar包。
在這裏插入圖片描述
這樣,當把咱們的maven項目部署到本地tomcat服務器上去時,就會存在這倆jar包衝突的問題,所以纔會報錯。即使現在使用的是maven裏面帶有的tomcat7插件運行maven項目,那也會報相同的錯誤。

要想解決該問題,就不得不知道依賴的作用範圍了。下面我將會花大量的篇幅來介紹它。

依賴管理

依賴配置

在maven中,是在pom.xml文件中完成依賴的配置的,我們先來看看依賴配置的語法。

<project>
    ...
    <!-- 添加依賴 -->
    </dependencies>
        <dependency>
            <groupId>...</groupId>
            <artifactId>...</artifactId>
            <version>...</version>
            <type>...</type>
            <scope>...</scope>
            <optional>...</optional>
            <exclusions>
                <exclusion>
                    ...
                </exclusion>
            </exclusions>
        </dependency>

        ...
    </dependencies>
    ...
<project>

乍一看,這個配置還是蠻複雜的,其實我們常用的沒有這麼多,而且這些用起來也是非常簡單的。在pom.xml文件中,根元素project下的dependencies標籤中可以包含一個或者多個dependency元素,以聲明一個或者多個項目依賴。每個依賴dependency標籤中都應該包含以下元素:
在這裏插入圖片描述
很多時候,大部分依賴聲明只包含groupId、artifactId和version這三個指定基本座標的元素;而在一些特殊情況下,其它元素至關重要,也就是上面提到的scope、optional和exclusions。下面我只對scope這個元素進行詳細的介紹。

依賴範圍

依賴範圍是什麼?

我們需要知道,maven在編譯項目主代碼的時候需要使用一套classpath。舉例來說:
在這裏插入圖片描述
所以,依賴範圍就是用來控制依賴與這三種classpath(編譯classpath、測試classpath、運行classpath)的關係的。

依賴範圍具體有哪些?

scope(依賴範圍)共有五種,它們分別是compile、provided、runtime、test、system。如果你記不起來這五種依賴範圍也沒關係,藉助eclipse這個IDE就能知曉了,按照下圖所示的步驟來操作即可。
在這裏插入圖片描述
下面我會一一詳細地介紹每一種依賴範圍。

compile

編譯依賴範圍。如果沒有指定scope值,那麼就會默認使用該依賴。使用該依賴範圍的maven依賴,對於編譯、測試、運行這三種classpath都有效。

就以前一講中的maven項目來說,由於沒有顯示指定scope值,所以下面這兩個依賴都是使用的編譯依賴範圍。
在這裏插入圖片描述
如果將該maven項目部署到本地tomcat服務器中,並啓動本地tomcat服務器,那麼就能在本地tomcat服務器的webapps目錄下看到該maven項目了。
在這裏插入圖片描述
而且還會發現該maven項目的WEB-INF\lib目錄下有如下3個jar包。
在這裏插入圖片描述
而我們知道本地tomcat服務器的lib目錄中已經存在servlet-api.jar和jsp-api.jar這倆jar包了,所以這個時候就會發生jar包衝突的情況。只要在Google Chrome瀏覽器中訪問HelloServlet,就會報一開始出現的錯誤。

provided

已提供依賴範圍。使用此依賴範圍的maven依賴,對於編譯和測試classpath有效,但在運行時無效。最典型的例子是servlet-api,編譯和測試項目的時候需要該依賴,但在運行項目的時候,由於tomcat容器已經提供,所以就不需要maven重複地引入一遍了。

還是以前一講中的maven項目來說,現在我們將下面兩個依賴的scope置爲provided。也有兩種方式來完成這一操作,第一種方式是手動在每一個依賴中添加<scope>provided</scope>

<!-- 添加依賴 -->
<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

第二種方式是直接利用eclipse就可以很方便地爲每一個依賴添加<scope>provided</scope>了,大家按照下圖所示的步驟進行操作即可。
在這裏插入圖片描述
點擊OK按鈕,再保存一下pom.xml文件,這時你會發現pom.xml文件變成了下面這個樣子。
在這裏插入圖片描述
再將該maven項目部署到本地tomcat服務器中,並啓動本地tomcat服務器,雖然你會發現本地tomcat服務器的webapps目錄下還是會有該maven項目,但是該maven項目的WEB-INF目錄下直接沒有lib目錄了。
在這裏插入圖片描述
這就說明沒有jar包衝突的情況發生了。這時,在Google Chrome瀏覽器中訪問HelloServlet,你就會看到如下圖所示的效果了。
在這裏插入圖片描述
就算是你現在使用maven裏面帶有的tomcat7插件來運行maven項目,然後同樣在Google Chrome瀏覽器中訪問HelloServlet,你依然會看到同樣的結果,報錯是不可能的了。

runtime

運行時依賴範圍。使用此依賴範圍的maven依賴,對於測試和運行classpath有效,但在編譯主代碼時無效。最典型的例子就是JDBC驅動實現,項目主代碼的編譯只需要JDK提供的JDBC接口,只有在執行測試或者運行項目的時候才需要實現上述接口的具體JDBC驅動。

test

測試依賴範圍。使用此依賴範圍的maven依賴,只對於測試classpath有效,在編譯主代碼或者運行項目時都無法使用此依賴。最典型的例子就是JUnit,它只有在編譯測試代碼及運行測試用例的時候才需要。也就是說,在編譯和測試時是需要的,但在運行時不需要,因爲在測試的時候,我們是用來跑測試用例的,而將來把項目打成jar包或者war包,丟到服務器上去,還要跑測試用例嗎?肯定是不需要的。

system

系統依賴範圍。該依賴與三種classpath的關係和provided依賴範圍完全一致。但是,使用system範圍的依賴時必須通過systemPath元素顯式地指定依賴文件的路徑。由於此類依賴不是通過maven倉庫解析的,而且往往與本機系統綁定,可能造成構建的不可移植,因此謹慎使用。system的使用例子如下:

<dependencies>
    <dependency>
        <groupId>com.jellythink.BookStore</groupId>
        <artifactId>BookStore-SSO</artifactId>
        <version>1.0</version>
        <scope>system</scope>
        <systemPath>${basedir}/lib/BookStore-SSO-1.0.jar</systemPath>
    </dependency>
</dependencies>

對於system系統依賴範圍,在進行以上配置以後,編寫代碼時已經可以引入jar包中的class了,但是在打包時,由於scope爲system,默認並不會將依賴包打進war包中,所以需要通過插件進行打包。例如:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.10</version>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>compile</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
                <includeScope>system</includeScope>
            </configuration>
        </execution>
    </executions>
</plugin>

總結

爲了更好的理解和記憶依賴範圍與classpath的關係,可以將上述內容總結成一張表格。
在這裏插入圖片描述

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