日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作者 | 京東云開發者-京東物流 龔航林

原文鏈接:https://my.oschina.NET/u/4090830/blog/10116011

1 SPI 簡介1.1 SPI(Service Provider Interface)

本質:將接口實現類的全限定名配置在文件中,并由服務加載器讀取配置文件,加載實現類。這樣可以在運行時,動態為接口替換實現類。

JAVA SPI:用來設計給服務提供商做插件使用的。基于策略模式來實現動態加載的機制。我們在程序只定義一個接口,具體的實現交個不同的服務提供者;在程序啟動的時候,讀取配置文件,由配置確定要調用哪一個實現。

dubbo SPI:在 dubbo 中也有 SPI 機制,雖然都需要將接口全限定名配置在文件中,但是 dubbo 并沒有使用 java 的 spi 機制,而是重新實現了一套功能更強的 SPI 機制,支持了 AOP 與依賴注入,并且 利用緩存提高加載實現類的性能,同時 支持實現類的靈活獲取。基于 SPI,我們可以很容易的對 Dubbo 進行拓展。例如 dubbo 當中的 protocol,LoadBalance 等都是通過 SPI 機制擴展。

2 java SPI2.1 實現過程

1)需要在 classpath 下創建一個目錄,該目錄命名必須是:META-INF/service

2)在該目錄下創建一個 文本文件,該文件需要滿足以下幾個條件

  • 文件名必須是擴展的接口的全路徑名稱
  • 文件內部描述的是該擴展接口的所有實現類
  • 文件的編碼格式是 UTF-8

3)通過 java.util.ServiceLoader 的加載機制來加載服務

深入理解java和dubbo的SPI機制

深入理解java和dubbo的SPI機制

2.2 工作原理

1)當調用 ServiceLoader.load (Class clz) 方法時,會到 jar 中中的目錄 “META-INF/services/“ + clz.getName 進行文件讀取,

2)當在調用 ServiceLoader.forEach 方法時,實際走的是 LazyIterator,當在調用 LazyIterator.hasNext 時,在文件中讀取到實際的服務實現類并把它們通過調用 Class.forName (String name, boolean initialize,ClassLoader loader)。

深入理解java和dubbo的SPI機制

2.3 實際應用

javaSPI 我們最熟悉的應用就是數據庫驅動了,MySQL 和 oracle 驅動針對 JDBC 分別有自己的實現,這就有賴于 java 的 SPI 機制。

深入理解java和dubbo的SPI機制

3 dubbo SPI3.1 實現過程

1)需要在 classpath 下創建一個目錄,該目錄命名可以是:META-INF/service/、META-INF/dubbo/、META-INF/dubbo/internal/

2)在該目錄下創建一個 文本文件,該文件需要滿足以下幾個條件

  • 文件名必須是擴展的接口的全路徑名稱
  • 文件內部描述的是該擴展接口的所有實現類,將服務實現類寫成 KV 鍵值對的形式,Key 是拓展類的 name,Value 是擴展的全限定名實現類。

3)通過 org.Apache.dubbo.common.extension.Extensier 的加載機制來加載服務

深入理解java和dubbo的SPI機制

深入理解java和dubbo的SPI機制

3.2 工作原理

1)我們首先通過 Extensier 的 getExtensier 方法獲取一個接口的 Extensier 實例,然后再通過 Extensier 的 getExtension 方法獲取拓展類對象,源碼如下,首先是 getExtensier 方法:

深入理解java和dubbo的SPI機制

new Extensier (type) 源碼如下:

注意這里創建 Extensier 對象的構造方法如下:Extensier.getExtensier 獲取 ExtensionFactory 接口的拓展類,再通過 getAdaptiveExtension 從拓展類中獲取目標拓展類。

2)通過 Extensier.getExtensier 取到接口的加載器 Loader 之后,再通過 getExtension 方法獲取需要拓展類對象。

深入理解java和dubbo的SPI機制

以上代碼首先檢查 holder 中的實例緩存,緩存未命中則創建拓展對象。dubbo 中包含了大量的擴展點緩存。這個就是典型的使用空間換時間的做法。

深入理解java和dubbo的SPI機制

創建拓展類對象步驟分別為:

  1. 通過 getExtensionClasses 從配置文件中加載所有的拓展類,再通過名稱獲取目標拓展類
  2. 通過反射創建拓展對象
  3. 向拓展對象中注入依賴
  4. 將拓展對象包裹在相應的 WrApper 對象中

我們接下來重點看下 getExtensionClasses 方法:

深入理解java和dubbo的SPI機制

先從緩存中獲取 class,緩存未命中則調用 loadExtensionClasses 方法加載,我們再看下 loadExtensionClasses 這個方法:

我們看到這里遍歷調用了多個策略去加載 class 的,跟到這里我們發現非常有意思的是:dubbo 在加載 META-INF 目錄下的 class 鍵值對的時候采用了 javaSPI 的方式

深入理解java和dubbo的SPI機制

深入理解java和dubbo的SPI機制

這里 dubbo 使用 javaSPI 的方式加載到 3 中類加載策略:

org.apache.dubbo.common.extension.DubboInternalLoadingStrategy 用于加載 META-INF/dubbo/internal/ 中的 class

org.apache.dubbo.common.extension.DubboLoadingStrategy 用于加載 META-INF/dubbo/ 中的 class

org.apache.dubbo.common.extension.ServicesLoadingStrategy 用于加載 META-INF/service/ 中的 class

dubbo 的 SPI 還提供了自適應(Adaptive)、自動注入的功能就不在這里過多展開了,有興趣可以自行了解。

3.3 實際應用

dubbo 中大量使用了 SPI 機制:

深入理解java和dubbo的SPI機制

例如 dubbo 的多協議的實現:

深入理解java和dubbo的SPI機制

4 javaSPI 和 dubboSPI 對比

  1. Java SPI 在加載擴展點的時候,會一次性加載所有可用的擴展點,很多是不需要的,會浪費系統資源。dubboSPI 有選擇性地加載所需要的 SPI 接口。
  2. javaSPI 配置文件中只是簡單的列出了所有的擴展實現,而沒有給他們命名。導致在程序中很難去準確的引用它們。而 dubboSPI 配置文件中以鍵值對的形式有別名,易于區分。
  3. SPI 擴展如果依賴其他的擴展,javaspi 做不到自動注入和裝配,dubbo 可以實現自動注入。
  4. javaSPI 不提供類似于 Spring 的 IOC 和 AOP 功能,dubboSPI 是支持的

分享到:
標簽:java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定