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

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

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

你應該了解的 Java SPI 機制

作者:crossoverJie

前言

不知大家現在有沒有去公司復工,我已經在家辦公將近 3 周了,同時也在家呆了一個多月;還好工作并沒有受到任何影響,我個人一直覺得遠程工作和 IT 行業是非常契合的,這段時間的工作效率甚至比在辦公室還高,同時由于我們公司的業務在海外,所以疫情幾乎沒有造成太多影響。

扯遠了,這次主要是想和大家分享一下 JAVA 的 SPI 機制。周末沒啥事,我翻了翻我之前的寫的博客 《設計一個可拔插的 IOC 容器》,發現當時的實現并不那么優雅。

還沒看過的朋友的我先做個前景提要,當時的需求:

我實現了一個類似于的 SpringMVC 但卻很輕量的 http 框架 cicada,其中當然也需要一個 IOC 容器,可以存放所有的單例 bean。這個 IOC 容器的實現我希望可以有多種方式,甚至可以提供一個接口供其他人實現;當然切換這個 IOC 容器的過程肯定是不能存在硬編碼的,也就是這里所提到的可拔插。當我想使用 A 的實現方式時,我就引入 A 的 jar 包,使用 B 時就引入 B 的包。

 

你應該了解的 Java SPI 機制

 

先給大家看看兩次實現的區別,先從代碼簡潔程度來說就是 SPI 更勝一籌。

什么是 SPI

在具體分析之前還是先了解下 SPI 是什么?

首先它其實是 Service provider interface的簡寫,翻譯成中文就是服務提供發現接口。

不過這里不要被這個名詞搞混了,這里的服務發現和我們常聽到的微服務中的服務發現并不能劃等號。

就如同上文提到的對 IOC 容器的多種實現方式 A、B、C(可以把它們理解為服務),我需要在運行時知道應該使用哪一種具體的實現。

其實本質上來說這就是一種典型的面向接口編程,這一點在我們剛開始學習編程的時候就被反復強調了。

SPI 實踐

接下來我們來如何來利用 SPI 實現剛才提到的可拔插 IOC 容器。

既然剛才都提到了 SPI 的本質就是面向接口編程,所以自然我們首先需要定義一個接口:

 

你應該了解的 Java SPI 機制

 

其中包含了一些 Bean 容器所必須的操作:注冊、獲取、釋放 bean。

為了讓其他人也能實現自己的 IOC 容器,所以我們將這個接口單獨放到一個 Module中,可供他人引入實現。

 

你應該了解的 Java SPI 機制

 

所以當我要實現一個單例的 IOC 容器時,我只需要新建一個 Module 然后引入剛才的模塊并實現 CicadaBeanFactory 接口即可。

當然其中最重要的則是需要在 resources目錄下新建一個 META-INF/services/top.crossoverjie.cicada.base.bean.CicadaBeanFactory 文件,文件名必須得是我們之前定義接口的全限定名(SPI 規范)。

 

你應該了解的 Java SPI 機制

 

其中的內容便是我們自己實現類的全限定名:

top.crossoverjie.cicada.bean.ioc.CicadaIoc

可以想象最終會通過這里的全限定名來反射創建對象。

只不過這個過程 Java 已經提供 API 屏蔽掉了:

public static CicadaBeanFactory getCicadaBeanFactory() {

ServiceLoader<CicadaBeanFactory> cicadaBeanFactories = ServiceLoader.load(CicadaBeanFactory.class);

if (cicadaBeanFactories.iterator().hasNext()){

return cicadaBeanFactories.iterator().next() ;

}

return new CicadaDefaultBean();

}

當 classpath 中存在我們剛才的實現類(引入實現類的 jar 包),便可以通過 java.util.ServiceLoader 工具類來找到所有的實現類(可以有多個實現類同時存在,只不過通常我們只需要一個)。


一些都準備好之后,使用自然就非常簡單了。

<dependency>

<groupId>top.crossoverjie.opensource</groupId>

<artifactId>cicada-ioc</artifactId>

<version>2.0.4</version>

</dependency>


我們只需要引入這個依賴便能使用它的實現,當我們想換一種實現方式時只需要更換一個依賴即可。

這樣就做到了不修改一行代碼靈活的可拔插選擇 IOC 容器了。

SPI 的一些其他應用

雖然平時并不會直接使用到 SPI 來實現業務,但其實我們使用過的絕大多數框架都會提供 SPI 接口方便使用者擴展自己的功能。

比如 Dubbo 中提供一系列的擴展:

 

你應該了解的 Java SPI 機制

同類型的 RPC 框架 motan 中也提供了響應的擴展:

 

你應該了解的 Java SPI 機制

 

他們的使用方式都和 Java SPI 非常類似,只不過原理略有不同,同時也新增了一些功能。

比如 motan 的 spi 允許是否為單例等等。

再比如 MySQL 的驅動包也是利用 SPI 來實現自己的連接邏輯。

 

你應該了解的 Java SPI 機制

 

總結

Java 自身的 SPI 其實也有點小毛病,比如:

  • 遍歷加載所有實現類效率較低。
  • 當多個 ServiceLoader 同時 load 時會有并發問題(雖然沒人這么干)。

最后總結一下,SPI 并不是某項高深的技術,本質就是面向接口編程,而面向接口本身在我們日常開發中也是必備技能,所以了解使用 SPI 也是很用處的。

原文:https://www.jianshu.com/p/96e178542f7b

本文所有源碼:

https://github.com/TogetherOS/cicada

分享到:
標簽:機制 Java SPI
用戶無頭像

網友整理

注冊時間:

網站: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

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