SpringCloud升級之路2020.0.x版-4.maven依賴回顧以及專案框架結構

乾貨滿滿張雜湊發表於2021-08-04

本系列程式碼地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford

image

我們先來回顧下 maven 依賴中一個重要原則:最短路徑原則。這在之後我們的使用中會經常用到。

舉一個例子,假設我們以 spring-boot-parent 作為 parent:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.9</version>
</parent>

我們想用想用 elasticsearch 作為搜尋引擎,在專案中新增了依賴

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.10.2</version>
</dependency>

寫好程式碼,一跑,報類不存在異常:

 java.lang.NoClassDefFoundError: org/elasticsearch/common/xcontent/DeprecationHandler
    at com.lv.springboot.datasource.ClientUTis.main(ClientUTis.java:13)
Caused by: java.lang.ClassNotFoundException: org.elasticsearch.common.xcontent.DeprecationHandler
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

看下依賴mvn dependency:tree,發現依賴的elasticsearch版本是:

org.elasticsearch.client:elasticsearch-rest-high-level-client:7.0.1
|--org.elasticsearch:elasticsearch:5.6.16
|--org.elasticsearch.client:elasticsearch-rest-client:7.0.1
|--org.elasticsearch.plugin:parent-join-client:7.0.1
|--org.elasticsearch.plugin:aggs-matrix-stats-client:7.0.1
|--org.elasticsearch.plugin:rank-eval-client:7.0.1
|--org.elasticsearch.plugin:lang-mustache-client:7.0.1

可能讀者會感覺很奇怪,明明指定了elasticsearch的依賴了啊,而且是專案的根 pom,依賴不是最短路徑原則麼?不應該以這個依賴為準麼?

仔細分析,原來 SpringBoot的DependencyManagement 中,org.elasticsearch:elasticsearch已經被包含了(以下為節選):

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.9.RELEASE</version>

<properties>
<elasticsearch.version>5.6.16</elasticsearch.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

spring-boot 其實已經考慮到使用者可能要換版本了,所以將版本放入了 <properties/>,properties 也具有最短路徑原則,所以可以通過在你的專案根 pom 中的 properties 增加相同 key 修改版本:

<properties>
    <elasticsearch.version>7.10.2</elasticsearch.version>
</properties>

所有可以這麼替換的屬性, spring-boot 官方文件已經列出了,參考官方文件附錄:Version Properties

也可以通過 dependencyManagement 的最短路徑原則,通過在你的專案根 pom 中的增加想修改依賴的 dependencyManagement 即可:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.10.2</version>
        </dependency>
    </dependencies>
</dependencyManagement>

最後,可以記住下面的原則,就知道專案的依賴到底是哪個版本啦:

Maven依賴可以分為如下幾部分:

  1. 直接依賴,就是本專案 dependencies 部分的依賴
  2. 間接依賴,就是本專案 dependencies 部分的依賴所包含的依賴
  3. 依賴管理,就是本專案 dependency management 裡面的依賴
  4. parent 的直接依賴
  5. parent 的間接依賴
  6. parent 的依賴管理
  7. bom 的直接依賴(一般沒有)
  8. bom 的間接依賴(一般沒有)
  9. bom 的依賴管理

可以這麼理解依賴:

  1. 首先,將 parent 的直接依賴,間接依賴,還有依賴管理,插入本專案,放入本專案的直接依賴,間接依賴還有依賴管理之前
  2. 對於直接依賴,如果有 version,那麼就依次放入 DependencyMap 中。如果沒有 version,則從依賴管理中查出來 version,之後放入 DependencyMap 中。key 為依賴的 groupId + artifactId,value為version,後放入的會把之前放入的相同 key 的 value 替換
  3. 對於每個依賴,各自按照 1,2 載入自己的 pom 檔案,但是如果第一步中的本專案 dependency management 中有依賴的版本,使用本專案 dependency management的依賴版本,生成 TransitiveDependencyMap,這裡面就包含了所有的間接依賴。
  4. 所有間接依賴的 TransitiveDependencyMap, 對於專案的 DependencyMap 裡面沒有的 key,依次放入專案的 DependencyMap
  5. 如果 TransitiveDependencyMap 裡面還有間接依賴,那麼遞迴執行3, 4。

由於是先放入本專案的 DependencyMap,再去遞迴 TransitiveDependencyMap,這就解釋了 maven 依賴的最短路徑原則。

Bom 的效果基本和 Parent 一樣,只是一般限制中,Bom 只有 dependencyManagement 沒有 dependencies

image

如下圖所示,我們會抽象出如下幾個依賴:

image

  1. 所有專案的 parent:以某版本 Spring Boot 作為 parent,管理 Spring Cloud 依賴,並且包括一些公共依賴,還有單元測試依賴。如果以後我們想修改 Spring Boot 或者 Spring Cloud 版本,就在這裡修改。並且,指定了所有專案編譯配置。
  2. Spring Framework Common:所有使用了 Spring 或者 Spring Boot 的公共依賴,一般我們編寫 starter,或者編寫一些工具包,不需要 Spring Cloud 的特性,就會新增這個依賴。
  3. Spring Cloud Common:新增了 Spring Framework Common 的依賴。我們的微服務分為主要基於 spring-webmvc 的同步微服務專案以及主要基於 spring-webflux 的非同步微服務專案,其中有一些公共的依賴和程式碼,就放在了這個專案中。
  4. Spring Cloud WebMVC:新增了 Spring Cloud Common 的依賴。基於 spring-webmvc 的同步微服務專案需要新增的核心依賴。
  5. Spring Cloud WebFlux:新增了 Spring Cloud Common 的依賴。基於 spring-webflux 的非同步微服務專案需要新增的核心依賴。

我們在微服務專案中主要使用的依賴為:

  1. 對於純工具包,只使用了 Spring 與 Spring Boot 的特性的,新增 Spring Framework Common 的依賴。
  2. 對於基於 spring-webmvc 的同步微服務專案,新增 Spring Cloud WebMVC 的依賴。
  3. 對於基於 spring-webflux 的非同步微服務專案,新增 Spring Cloud WebFlux 的依賴。

本小節我們回顧了並深入理解了 maven 依賴最短路徑原則,然後給出了我們專案框架的結構,主要對外提供了三種依賴:只使用了 Spring 與 Spring Boot 的特性的依賴,對於基於 spring-webmvc 的同步微服務專案的依賴以及對於基於 spring-webflux 的非同步微服務專案的依賴。下一節我們將對這些專案模組的 pom 檔案進行詳細分析。

微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer

相關文章