本系列程式碼地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford
我們先來回顧下 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依賴可以分為如下幾部分:
- 直接依賴,就是本專案 dependencies 部分的依賴
- 間接依賴,就是本專案 dependencies 部分的依賴所包含的依賴
- 依賴管理,就是本專案 dependency management 裡面的依賴
- parent 的直接依賴
- parent 的間接依賴
- parent 的依賴管理
- bom 的直接依賴(一般沒有)
- bom 的間接依賴(一般沒有)
- bom 的依賴管理
可以這麼理解依賴:
- 首先,將 parent 的直接依賴,間接依賴,還有依賴管理,插入本專案,放入本專案的直接依賴,間接依賴還有依賴管理之前
- 對於直接依賴,如果有 version,那麼就依次放入 DependencyMap 中。如果沒有 version,則從依賴管理中查出來 version,之後放入 DependencyMap 中。key 為依賴的 groupId + artifactId,value為version,後放入的會把之前放入的相同 key 的 value 替換
- 對於每個依賴,各自按照 1,2 載入自己的 pom 檔案,但是如果第一步中的本專案 dependency management 中有依賴的版本,使用本專案 dependency management的依賴版本,生成 TransitiveDependencyMap,這裡面就包含了所有的間接依賴。
- 所有間接依賴的 TransitiveDependencyMap, 對於專案的 DependencyMap 裡面沒有的 key,依次放入專案的 DependencyMap
- 如果 TransitiveDependencyMap 裡面還有間接依賴,那麼遞迴執行3, 4。
由於是先放入本專案的 DependencyMap,再去遞迴 TransitiveDependencyMap,這就解釋了 maven 依賴的最短路徑原則。
Bom 的效果基本和 Parent 一樣,只是一般限制中,Bom 只有 dependencyManagement 沒有 dependencies
如下圖所示,我們會抽象出如下幾個依賴:
- 所有專案的 parent:以某版本 Spring Boot 作為 parent,管理 Spring Cloud 依賴,並且包括一些公共依賴,還有單元測試依賴。如果以後我們想修改 Spring Boot 或者 Spring Cloud 版本,就在這裡修改。並且,指定了所有專案編譯配置。
- Spring Framework Common:所有使用了 Spring 或者 Spring Boot 的公共依賴,一般我們編寫 starter,或者編寫一些工具包,不需要 Spring Cloud 的特性,就會新增這個依賴。
- Spring Cloud Common:新增了 Spring Framework Common 的依賴。我們的微服務分為主要基於 spring-webmvc 的同步微服務專案以及主要基於 spring-webflux 的非同步微服務專案,其中有一些公共的依賴和程式碼,就放在了這個專案中。
- Spring Cloud WebMVC:新增了 Spring Cloud Common 的依賴。基於 spring-webmvc 的同步微服務專案需要新增的核心依賴。
- Spring Cloud WebFlux:新增了 Spring Cloud Common 的依賴。基於 spring-webflux 的非同步微服務專案需要新增的核心依賴。
我們在微服務專案中主要使用的依賴為:
- 對於純工具包,只使用了 Spring 與 Spring Boot 的特性的,新增 Spring Framework Common 的依賴。
- 對於基於 spring-webmvc 的同步微服務專案,新增 Spring Cloud WebMVC 的依賴。
- 對於基於 spring-webflux 的非同步微服務專案,新增 Spring Cloud WebFlux 的依賴。
本小節我們回顧了並深入理解了 maven 依賴最短路徑原則,然後給出了我們專案框架的結構,主要對外提供了三種依賴:只使用了 Spring 與 Spring Boot 的特性的依賴,對於基於 spring-webmvc 的同步微服務專案的依賴以及對於基於 spring-webflux 的非同步微服務專案的依賴。下一節我們將對這些專案模組的 pom 檔案進行詳細分析。
微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer: