Maven學習(二) -- 坐標和依賴


標簽(空格分隔): 學習筆記


坐標

實際就像在幾何中,我們用一對坐標(x, y)來表示坐標系中唯一的點;或者我們可以用(經度,緯度)來表示地球上的某一個位置,在Maven的世界中,有坐標來唯一的表示項目。

他們由groupId, artifactId, version, packaging, classifier等信息唯一的標識。

依賴

Maven會根據在POM中妹紙的信息自動下載所需要的依賴構件。

依賴的配置

<project>
    <dependencies>
        <dependency>
            <groupId>...</groupId>
            <artifactId>...</artifactId>
            <version>...</version>
            <type>...</type>
            <scope>...</scope>
            <optional>...</optional>
            <exclusions>
                <exclusion>
                    ...
                </exclusion>
                ...
            </exclusions>
        </dependency>
        ...
    </dependencies>
    ...
</project>

其中,上述依賴元素的意義:

  • groupId, artifactId, version:依賴的基本坐標,對於任何一個依賴來說,基本坐標是最重要的,Maven根據坐標才能找到需要的依賴;
  • type: 依賴的類型,對應於項目坐標蒂尼的packaging,大部分情況下為jar;
  • scope: 依賴的范圍。
  • optional: 標記依賴是否可選;
  • exclusions: 用來排除傳遞性依賴。

依賴范圍

這里的依賴范圍主要針對上面scope而言。
Maven在編譯項目主代碼的時候需要使用一套classpath,其中,編譯,測試,運行使用不同的classpath。

依賴范圍就是用來控制依賴於這三種classpath(編譯classpath,測試classpath,運行classpath)的關系的。。。

  • compile: 編譯依賴范圍。如果沒有指定,則默認使用該依賴范圍。使用此依賴范圍的Maven依賴,對於編譯,運行,測試三種classpath都有效。典型的例子是spring-core.
  • test: 測試依賴范圍。典型的例子是JUnit.
  • provided: 已提供依賴范圍。對於編譯和測試classpath有效,而對運行classpath無效。典型的例子是servlet-api,編譯和測試項目的時候需要該依賴,但在運行項目的時候,由於容器已經提供,就不需要Maven重復的引入了。
  • runtime: 運行時依賴范圍。對於測試和運行都有效。典型的例子是JDBC。在項目編譯的時候只需要JDK提供JDBC接口,只有在運行或測試的時候才需要實現上述接口的具體JDBC驅動。
  • system: 系統依賴范圍。編譯和測試時有效,應是無效。但使用system范圍的依賴時必須通過systemPath元素顯示地指定依賴文件的路徑。由於此類依賴不是通過Maven倉庫解析的,而且往往與本機系統綁定,可能造成構建的不可移植,因此應謹慎使用。
  • import: 導入依賴范圍。

傳遞性依賴

一個機遇Spring Framework的項目,如果不使用Maven,則在項目中就需要手動下載相關依賴:
做法一:下載一個很大的如spring-framework-2.5.6-with-dependencies.zip的包,這里包含了所有Spring Frame的jar包,以及依賴的所有其他jar包,但這樣往往會導致引入了很多不必要的依賴;
做法二:只下載spring-framework-2.5.6.zip的包,到實際應用的時候根據其出錯信息,再依次下載其他的包。
上面兩種做法實際都是很繁瑣的,在Maven中可以使用依賴性傳遞來解決這個問題。Maven會解析各個直接依賴的POM。將那些必要的間接依賴,以傳遞性依賴的形式引入到當前的項目中。

排除傳遞性依賴

例如如下場景:

  • 場景一:當前項目中有一個第三方依賴,而這個第三方依賴由於某些原因依賴了另外一個類庫的SNAPSHOT版本(該類庫就成了項目的傳遞依賴),而SNAPSHOT可能是不穩定的,則必然會影響到該項目的穩定性,因此希望能夠將這個傳遞依賴切除。
  • 場景二:希望能夠替換某個傳遞性依賴。例如一個項目A依賴一個類庫X,而由於版本的原因,這個類庫並不在中央倉庫中。但是某個公司有個類似的實現包Y。所以我們想做的是將X的依賴切除,然后聲明對Y的依賴。

排除傳遞性依賴實例:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.park.mvnDemo</groupId>
    <artifactId>project-a</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>com.park.mvn</groupId>
            <artifactId>project-b</artifactId>
            <version>1.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.park.mvnDemo</groupId>
                    <artifactId>project-c</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.park.mvnDemo</groupId>
            <artifactId>project-c</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</project>

需要注意的是:聲明exclusions的時候只需要groupId和artifactId,而不需要version,就可以唯一的定位依賴圖中的某個依賴。(Maven解析后,不可能出現groupId和artifactId相同,但version不同的兩個依賴。)

依賴調解

  • 第一原則:路徑最近者優先;
  • 第二原則:第一聲明優先。
  • 在依賴路徑長度相等的前提下,在POM中依賴聲明的順序決定了誰會被解析使用,順序最靠前的那個依賴優勝。

在理想情況下,是不應該使用可選依賴的。使用的原因是:某一個項目實現了多個特性,而且這些特性間是互斥的。

可選依賴不被傳遞

假設有這樣一個依賴關系:
項目A依賴於項目B,項目B依賴於項目X和Y,而且B對X和Y的依賴都是可選依賴:A->B, B->X(可選), B->Y(可選)。此時,X,Y將不會對A有任何影響,即可選傳遞不會傳遞下去。
可選依賴的配置:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juven.mvnDemo</groupId>
    <artifactId>project-b</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.10</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>8.4-701.jdbc3</version>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

歸類依賴

類似與Java中的常量定義,Maven中的依賴也應該在一個唯一的地方定義版本,並且在dependency聲明中引用這一版本。這樣,在升級一些包的時候只需要修改一處。
實例:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.park.mvnDemo.account</groupId>
    <artifactId>account-email</artifactId>
    <name>Account Email</name>
    <version>1.0.0</version>
    
    <properties>
        <springframework.version>2.5.6</springframework.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${springframework.version}</version>
        </dependency>
    </dependencies>
</project>

這里,使用<properties> <springframework.version>2.5.6</springframework.version> </properties>定義一個Maven屬性,然后后面使用${springframework.version}來使用這個屬性。

優化依賴

Maven會自動解析所有項目的直接依賴和傳遞性依賴,並且根據規則正確判斷每個依賴的范圍,對於一些依賴沖突,也能進行調節,以確保任何一個構件只有唯一的版本在依賴中存在。-- 得到的依賴成為已解析依賴(Resolved Dependency)

  • 查看項目中的已解析依賴:
  • 使用命令mvn dependency:list
  • 查看當前項目中的依賴樹:
  • 使用命令mvn dependency:tree
  • 分析當前項目中的依賴:
  • 使用命令mvn dependency:analyze.

如上便是Maven中依賴的主要內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM