深入學習Java中的SPI機制
概述
SPI(Service Provider Interface),是JDK內(nèi)置的一種服務(wù)提供發(fā)現(xiàn)機制,可以用來啟用框架擴展和替換組件,主要是被框架的開發(fā)人員使用,比如java.sql.Driver接口,其他不同廠商可以針對同一接口做出不同的實現(xiàn),MySQL和PostgreSQL都有不同的實現(xiàn)提供給用戶,而Java的SPI機制可以為某個接口尋找服務(wù)實現(xiàn)。
Java中SPI機制主要思想是將裝配的控制權(quán)移到程序之外,在模塊化設(shè)計中這個機制尤其重要,其核心思想就是解耦。
SPI整體機制圖如下
當服務(wù)的提供者提供了一種接口的實現(xiàn)之后,需要在classpath下的META-INF/services/目錄里創(chuàng)建一個以服務(wù)接口命名的文件,這個文件里的內(nèi)容就是這個接口的具體的實現(xiàn)類。當其他的程序需要這個服務(wù)的時候,就可以通過查找這個jar包(一般都是以jar包做依賴)的META-INF/services/中的配置文件,配置文件中有接口的具體實現(xiàn)類名,可以根據(jù)這個類名進行加載實例化,就可以使用該服務(wù)了。JDK中查找服務(wù)的實現(xiàn)的工具類是:java.util.ServiceLoader。
java.util.ServiceLoader
首先,ServiceLoader實現(xiàn)了Iterable接口,所以它有迭代器的屬性,這里主要都是實現(xiàn)了迭代器的hasNext和next方法。這里主要都是調(diào)用的lookupIterator的相應(yīng)hasNext和next方法,lookupIterator是懶加載迭代器。
其次,LazyIterator中的hasNext方法,靜態(tài)變量PREFIX就是”META-INF/services/”目錄,這也就是為什么需要在classpath下的META-INF/services/目錄里創(chuàng)建一個以服務(wù)接口命名的文件。
最后,通過反射方法Class.forName()加載類對象,并用newInstance方法將類實例化,并把實例化后的類緩存到providers對象中,(LinkedHashMap<String,S>類型) 然后返回實例對象。
demo
//定義一個接口HelloSPI。 package com.vivo.study.spidemo.spi; public interface HelloSPI { void sayHello(); } //完成接口的多個實現(xiàn)。 package com.vivo.study.spidemo.spi.impl; import com.vivo.study.spidemo.spi.HelloSPI; public class ImageHello implements HelloSPI { public void sayHello() { System.out.println("Image Hello"); } } package com.vivo.study.spidemo.spi.impl; import com.vivo.study.spidemo.spi.HelloSPI; public class TextHello implements HelloSPI { public void sayHello() { System.out.println("Text Hello"); } } //在META-INF/services/目錄里創(chuàng)建一個以com.vivo.study.spidemo.spi.HelloSPI的文件,這個文件里的內(nèi)容就是這個接口的具體的實現(xiàn)類。 內(nèi)容如下 com.vivo.study.spidemo.spi.impl.ImageHello com.vivo.study.spidemo.spi.impl.TextHello // 使用 ServiceLoader 來加載配置文件中指定的實現(xiàn) package com.vivo.study.spidemo.test import java.util.ServiceLoader; import com.vivo.study.spidemo.spi.HelloSPI; public class SPIDemo { public static void main(String[] args) { ServiceLoader<HelloSPI> serviceLoader = ServiceLoader.load(HelloSPI.class); // 執(zhí)行不同廠商的業(yè)務(wù)實現(xiàn),具體根據(jù)業(yè)務(wù)需求配置 for (HelloSPI helloSPI : serviceLoader) { helloSPI.sayHello(); } } } //輸出結(jié)果如下: Image Hello Text Hello
不足
1.不能按需加載,需要遍歷所有的實現(xiàn),并實例化,然后在循環(huán)中才能找到我們需要的實現(xiàn)。如果不想用某些實現(xiàn)類,或者某些類實例化很耗時,它也被載入并實例化了,這就造成了浪費。
2.獲取某個實現(xiàn)類的方式不夠靈活,只能通過 Iterator 形式獲取,不能根據(jù)某個參數(shù)來獲取對應(yīng)的實現(xiàn)類。
3.多個并發(fā)多線程使用 ServiceLoader 類的實例是不安全的。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Java和Dubbo的SPI機制原理解析
- Java 自旋鎖(spinlock)相關(guān)知識總結(jié)
- 深入理解Java中的SPI機制
- Java中SPI的一些理解
- 在java中使用SPI創(chuàng)建可擴展的應(yīng)用程序操作
- java中spi使用詳解
- Java 添加、刪除、替換、格式化Word中的文本的步驟詳解(基于Spire.Cloud.SDK for Java)
- Java 添加、刪除、格式化Word中的圖片步驟詳解( 基于Spire.Cloud.SDK for Java )
- Java 基于Spire.Cloud.SDK for Java在PDF中繪制形狀
- 詳解java實踐SPI機制及淺析源碼
- 淺談Java的SPI技術(shù)
- Java SPI的簡單小實例
- Java SPI機制原理及代碼實例
- 詳解JAVA SPI機制和使用方法
- Java基于Spire Cloud Excel把Excel轉(zhuǎn)換成PDF
- JAVA SPI特性及簡單應(yīng)用代碼實例
- Java進階之SPI機制詳解
相關(guān)文章
Java中如何將符號分隔的文本文件txt轉(zhuǎn)換為excel
這篇文章主要介紹了Java中如何將符號分隔的文本文件txt轉(zhuǎn)換為excel,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09SpringBoot 使用Prometheus采集自定義指標數(shù)據(jù)的方案
這篇文章主要介紹了SpringBoot 使用Prometheus采集自定義指標數(shù)據(jù),我們在k8s集群成功搭建了Prometheus服務(wù),今天,我們將在springboot2.x中使用prometheus記錄指標,需要的朋友可以參考下2022-10-10springboot中的Application.properties常用配置
這篇文章主要介紹了springboot中的Application.properties常用配置,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05Java用正則表達式實現(xiàn)${name}形式的字符串模板實例
這篇文章主要給大家介紹了Java如何用正則表達式實現(xiàn)${name}形式的字符串模板,文章給出詳細的實例代碼,對大家的理解和學習會很有幫助,有需要的朋友們下面來一起看看吧。2016-12-12解決運行jar包出錯:ClassNotFoundException問題
這篇文章主要介紹了解決運行jar包出錯:ClassNotFoundException問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12