Java開發學習(二十九)----Maven依賴傳遞、可選依賴、排除依賴解析

2022-09-02 09:03:35

現在的專案一般是拆分成一個個獨立的模組,當在其他專案中想要使用獨立出來的這些模組,只需要在其pom.xml使用<dependency>標籤來進行jar包的引入即可。

<dependency>其實就是依賴,關於依賴管理裡面都涉及哪些內容,我們就一個個來分析下:

  • 依賴傳遞

  • 可選依賴

  • 排除依賴

我們先來說說什麼是依賴:

依賴指當前專案執行所需的jar,一個專案可以設定多個依賴。

格式為:

<!--設定當前專案所依賴的所有jar-->
<dependencies>
    <!--設定具體的依賴-->
    <dependency>
        <!--依賴所屬群組id-->
        <groupId>org.springframework</groupId>
        <!--依賴所屬專案id-->
        <artifactId>spring-webmvc</artifactId>
        <!--依賴版本號-->
        <version>5.2.10.RELEASE</version>
    </dependency>
</dependencies>

一、依賴傳遞與衝突問題

1.1 依賴下鑽

比如下面的專案的依賴中

有一個比較大的區別就是有的依賴前面有箭頭>,有的依賴前面沒有。

那麼這個箭頭所代表的含義是什麼?開啟前面的箭頭,你會發現這個jar包下面還包含有其他的jar包

1.2 依賴具有傳遞性

說明:A代表自己的專案;B,C,D,E,F,G代表的是專案所依賴的jar包;D1和D2 E1和E2代表是相同jar包的不同版本

(1) A依賴了B和C,B和C有分別依賴了其他jar包,所以在A專案中就可以使用上面所有jar包,這就是所說的依賴傳遞

(2) 依賴傳遞有直接依賴和間接依賴

  • 相對於A來說,A直接依賴B和C,間接依賴了D1,E1,G,F,D2和E2

  • 相對於B來說,B直接依賴了D1和E1,間接依賴了G

  • 直接依賴和間接依賴是一個相對的概念

(3)因為有依賴傳遞的存在,就會導致jar包在依賴的過程中出現衝突問題,具體什麼是衝突?Maven是如何解決衝突的?

這裡所說的依賴衝突是指專案依賴的某一個jar包,有多個不同的版本,因而造成類包版本衝突。

情況一: 在pom.xml中新增兩個不同版本的Junit依賴:

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
​
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
</dependencies>

通過對比,會發現一個結論

  • 特殊優先:當同級設定了相同資源的不同版本,後設定的覆蓋先設定的。

情況二: 路徑優先:當依賴中出現相同的資源時,層級越深,優先順序越低,層級越淺,優先順序越高

  • A通過B間接依賴到E1

  • A通過C間接依賴到E2

  • A就會間接依賴到E1和E2,Maven會按照層級來選擇,E1是2度,E2是3度,所以最終會選擇E1

情況三: 宣告優先:當資源在相同層級被依賴時,設定順序靠前的覆蓋設定順序靠後的

  • A通過B間接依賴到D1

  • A通過C間接依賴到D2

  • D1和D2都是兩度,這個時候就不能按照層級來選擇,需要按照宣告來,誰先宣告用誰,也就是說B在C之前宣告,這個時候使用的是D1,反之則為D2

但是對應上面這些結果,大家不需要刻意去記它。因為不管Maven怎麼選,最終的結果都會在Maven的Dependencies面板中展示出來,展示的是哪個版本,也就是說它選擇的就是哪個版本

如果想更全面的檢視Maven中各個座標的依賴關係,可以點選Maven面板中的show Dependencies,例如

在這個檢視中就能很明顯的展示出jar包之間的相互依賴關係。

二、可選依賴和排除依賴

依賴傳遞介紹完以後,我們來思考一個問題,

  • maven_02_ssm 依賴了 maven_04_dao

  • maven_04_dao 依賴了 maven_03_pojo

  • 因為現在有依賴傳遞,所以maven_02_ssm能夠使用到maven_03_pojo的內容

  • 如果說現在不想讓maven_02_ssm依賴到maven_03_pojo,有哪些解決方案?

說明:在真實使用的過程中,maven_02_ssm中是需要用到maven_03_pojo的,我們這裡只是用這個例子描述我們的需求。因為有時候,maven_04_dao出於某些因素的考慮,就是不想讓別人使用自己所依賴的maven_03_pojo。

方案一:可選依賴

  • 可選依賴指對外隱藏當前所依賴的資源---指不透明

maven_04_dao的pom.xml,在引入maven_03_pojo的時候,新增optional

<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>maven_03_pojo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--可選依賴是隱藏當前工程所依賴的資源,隱藏後對應資源將不具有依賴傳遞-->
    <optional>true</optional>
</dependency>

此時就出問題了,說明由於maven_04_dao將maven_03_pojo設定成可選依賴,導致maven_02_ssm無法參照到maven_03_pojo中的內容,導致需要的類找不到。

方案二:排除依賴

  • 排除依賴指主動斷開依賴的資源,被排除的資源無需指定版本---指不需要

前面我們已經通過可選依賴實現了阻斷maven_03_pojo的依賴傳遞,對於排除依賴,則指的是已經有依賴的事實,也就是說maven_02_ssm專案中已經通過依賴傳遞用到了maven_03_pojo,此時我們需要做的是將其進行排除,所以接下來需要修改maven_02_ssm的pom.xml

<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>maven_04_dao</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--排除依賴是隱藏當前資源對應的依賴關係-->
    <exclusions>
        <exclusion>
            <groupId>com.itheima</groupId>
            <artifactId>maven_03_pojo</artifactId>
        </exclusion>
    </exclusions>
</dependency>

排除依賴資源僅需指定groupId,artifactId即可,不用指定version,會把不同的版本都排除掉

當然exclusions標籤帶s說明我們是可以依次排除多個依賴到的jar包,比如maven_04_dao中有依賴junit和mybatis,我們也可以一併將其排除。

<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>maven_04_dao</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--排除依賴是隱藏當前資源對應的依賴關係-->
    <exclusions>
        <exclusion>
            <groupId>com.itheima</groupId>
            <artifactId>maven_03_pojo</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

介紹我這兩種方式後,簡單來梳理下,就是

  • A依賴B,B依賴C,C通過依賴傳遞會被A使用到,現在要想辦法讓A不去依賴C

  • 可選依賴是在B上設定<optional>,A不知道有C的存在,代表這個依賴是否需要被發現。這種適用於可以修改B的組態檔的情況下

  • 排除依賴是在A上設定<exclusions>,A知道有C的存在,主動將其排除掉。代表這個依賴已經被發現,但自己是否需要參照。這種適用於不能修改B的組態檔的情況下