0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Java中的SPI動(dòng)態(tài)擴(kuò)展(上)

jf_78858299 ? 來源:碼農(nóng)參上 ? 作者:Dr Hydra ? 2023-03-24 14:27 ? 次閱讀

八股文背多了,相信大家都聽說過一個(gè)詞, SPI擴(kuò)展 。

有的面試官就很喜歡問這個(gè)問題,SpringBoot的自動(dòng)裝配是如何實(shí)現(xiàn)的?

基本上,你一說是基于spring的SPI擴(kuò)展機(jī)制,再把spring.factories文件和EnableAutoConfiguration提一下,那么這個(gè)問題就答的八九不離十了。

就像四五年前,我去面試的時(shí)候被問到這個(gè)問題,SPI動(dòng)態(tài)擴(kuò)展機(jī)制這幾個(gè)詞從嘴里一說出來,就把面試官唬的一愣一愣的??赡芩麄円矝]見過這么能裝逼的,一句話能簡(jiǎn)簡(jiǎn)單單說明白,非要拽一個(gè)聽上去很高大上的詞。

話說回來,被唬住的可不止是面試官,其實(shí)還有我自己。至于SPI擴(kuò)展究竟是個(gè)啥,是怎么實(shí)現(xiàn)的,我當(dāng)時(shí)也根本不明白。

不過現(xiàn)在的面試就是這樣,對(duì)線八股文,要想唬住面試官,就得先唬住自己。

那么我們今天暫且不提spring的SPI擴(kuò)展,先來看看java本身自帶的SPI擴(kuò)展機(jī)制是怎么一回事。

1、簡(jiǎn)介

SPI的全稱是Service Provider Interface,翻譯過來就是 服務(wù)提供者的接口 ,它所實(shí)現(xiàn)的其實(shí)是一種服務(wù)的發(fā)現(xiàn)機(jī)制。

這么說起來可能還是有點(diǎn)不好理解,我舉個(gè)例子來類比一下。

在spring項(xiàng)目中,寫service層代碼前,會(huì)約定俗成的會(huì)添加一個(gè)接口層。然后通過spring中的依賴注入,可以借助@Autowired等方式注入這個(gè)接口的實(shí)現(xiàn)類的實(shí)例對(duì)象,之后對(duì)于service的調(diào)用一般也基于接口操作。

簡(jiǎn)單形容就是這樣的:

圖片

如圖所示,接口、實(shí)現(xiàn)類都是由服務(wù)提供方提供,我們可以把controller看作服務(wù)調(diào)用者,調(diào)用方只管調(diào)用接口就可以了。

雖然也有聲音認(rèn)為,大部分情況下service只有一個(gè)實(shí)現(xiàn)類,接口層顯得有些多余。但是在《Head First Design Patterns》這本書中,大佬們還是建議過:

Program to an interface, not an implementation.

沒錯(cuò),就是常說的 要面向接口編程 。至于好處,也不外乎是降低耦合度、方便日后擴(kuò)展、提高了代碼的靈活性和可維護(hù)性等等。

在上面這個(gè)例子里,這個(gè)接口層和其中的方法我們可以稱之為 API ,而我們要討論的SPI和它相比,有類似也有差異,還是先看圖:

圖片

簡(jiǎn)單來說,就是服務(wù)的調(diào)用方定義一個(gè)接口規(guī)范,可以由不同的服務(wù)提供者實(shí)現(xiàn)。并且,調(diào)用方能夠通過某種機(jī)制來發(fā)現(xiàn)服務(wù)提供方,并通過接口調(diào)用它的能力。

通過對(duì)比,我們可以看出它們雖然都有著接口這一層面,但還是有很大的不同:

API中的接口是服務(wù)提供者給服務(wù)調(diào)用者的一個(gè)功能列表,而SPI中更多強(qiáng)調(diào)的是,服務(wù)調(diào)用者對(duì)服務(wù)實(shí)現(xiàn)的一種約束,服務(wù)提供者根據(jù)這種約束實(shí)現(xiàn)的服務(wù),可以被服務(wù)調(diào)用者發(fā)現(xiàn)。

說白了,Java中的SPI實(shí)現(xiàn)的就是,你按我的接口規(guī)范實(shí)現(xiàn)服務(wù),我就能通過某種機(jī)制為這個(gè)接口尋找到這個(gè)服務(wù)。

這么說起來可能還有些抽象,下面我們舉一個(gè)例子,類比具體描述一下這個(gè)過程。

2、定義接口

說起智能家居系統(tǒng),大家現(xiàn)在都比較熟悉了,只要是相同品牌下的產(chǎn)品,連上wifi就能夠通過手機(jī)app控制了,非常方便。

雖然產(chǎn)品不斷更新?lián)Q代,型號(hào)更新層出不窮,但是同種家電在app上操作起來,功能一般都是一樣的。就拿空調(diào)來說,我們?cè)赼pp上操作起來一般也就三個(gè)主要功能: 開關(guān) , 選模式 , 調(diào)節(jié)溫度

假設(shè)我現(xiàn)在在客廳、臥室、書房安裝了3款不同型號(hào)的空調(diào),并把它們都接入到了我app中,那么之后的操作都是相同的幾個(gè)按鍵,簡(jiǎn)單粗暴。

圖片

思考一下,無論是開關(guān)還是調(diào)溫,都是通過app去調(diào)用設(shè)備的接口罷了,那么如果不同型號(hào)的空調(diào)各寫各的接口,后端app在開發(fā)的時(shí)候光對(duì)接接口都麻煩的要死。

解決方法也很簡(jiǎn)單,我先定義一套接口規(guī)范,不管你以后什么型號(hào)的空調(diào),都按我的規(guī)范來實(shí)現(xiàn)接口。以后只要我能發(fā)現(xiàn)你的設(shè)備,那么都可以按相同的方法來調(diào)用接口。

那么下面就先來定義這么一套接口規(guī)范,如果你以后想要接入智能家居系統(tǒng),那么就要遵循這個(gè)規(guī)范來開發(fā)接口。

新建一個(gè)項(xiàng)目作為標(biāo)準(zhǔn),就叫aircondition-standard好了,然后創(chuàng)建一個(gè)接口。除了3個(gè)操作以外,我們?cè)偬砑右粋€(gè)獲取空調(diào)型號(hào)的方法。

public interface IAircondition {
    // 獲取型號(hào)
    String getType();
    
    // 開關(guān)
    void turnOnOff();

    // 調(diào)節(jié)溫度
    void adjustTemperature(int temperature);

    // 模式變更
    void changeModel(int modelId);
}

這個(gè)接口后面要給服務(wù)的實(shí)現(xiàn)方來使用,用maven把它打成jar包:

mvn clean install

之后服務(wù)提供者在項(xiàng)目中就可以引入這個(gè)jar包了,有了這套規(guī)范,就保證了產(chǎn)品后期不管怎么更新?lián)Q代,都能接入到系統(tǒng)來。

3、服務(wù)實(shí)現(xiàn)

制定并發(fā)布完規(guī)則后,掛式空調(diào)作為第一個(gè)服務(wù)提供者就來了,新建一個(gè)項(xiàng)目aircondition-hanging-type,并引入剛才打好的jar包:

<dependency>
    <groupId>com.cn.hydra<span class="hljs-name"groupId>
    <artifactId>aircondition-standard<span class="hljs-name"artifactId>
    <version>1.0-SNAPSHOT<span class="hljs-name"version>
<span class="hljs-name"dependency>

創(chuàng)建服務(wù)類,并實(shí)現(xiàn)前面定義的接口:

public class HangingTypeAircondition
        implements IAircondition{
    public String getType() {
        return "HangingType";
    }
    
    public void turnOnOff() {
        System.out.println("掛式空調(diào)開關(guān)");
    }

    public void adjustTemperature(int i) {
        System.out.println("掛式空調(diào)調(diào)節(jié)溫度");
    }

    public void changeModel(int i) {
        System.out.println("掛式空調(diào)更換模式");
    }
}

在項(xiàng)目的resources的目錄下,創(chuàng)建META-INF/services目錄,然后以前面定義的接口名com.cn.hydra.IAircondition創(chuàng)建文件,并在文件中寫入實(shí)現(xiàn)類的全限定名。

com.cn.hydra.HangingTypeAircondition

整個(gè)項(xiàng)目結(jié)構(gòu)非常簡(jiǎn)單:

圖片

這樣,一個(gè)服務(wù)方的簡(jiǎn)單實(shí)現(xiàn)就搞定了,用maven打成jar包,之后就可以提供給調(diào)用方使用了。

同理,我們可以再創(chuàng)建一個(gè)立式空調(diào)的項(xiàng)目aircondition-vertical-type,也只創(chuàng)建一個(gè)服務(wù)類:

public class VerticalTypeAircondition
        implements IAircondition{
    public String getType() {
        return "VerticalType";
    }
    
    public void turnOnOff() {
        System.out.println("立式空調(diào)開關(guān)");
    }

    public void adjustTemperature(int i) {
        System.out.println("立式空調(diào)調(diào)節(jié)溫度");
    }

    public void changeModel(int i) {
        System.out.println("立式空調(diào)更換模式");
    }
}

還是按上面的命名規(guī)則,創(chuàng)建一個(gè)配置文件:

com.cn.hydra.VerticalTypeAircondition

同樣,打成jar包就完事了,至于服務(wù)調(diào)用者如何去發(fā)現(xiàn)和調(diào)用這兩個(gè)服務(wù),下面詳細(xì)再說。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2948

    瀏覽量

    104390
  • SPI
    SPI
    +關(guān)注

    關(guān)注

    17

    文章

    1685

    瀏覽量

    91089
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4700

    瀏覽量

    68117
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    335

    瀏覽量

    14278
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    JAVA操作英創(chuàng)主板SPI接口簡(jiǎn)介

    的個(gè)數(shù),每一個(gè)SPITransfer需要用戶自己實(shí)例化?! ∽詈螅褂猛戤吅箨P(guān)閉SPI設(shè)備:  spi.Close();5、SPI測(cè)試程序運(yùn)行結(jié)果運(yùn)行SPI傳輸
    發(fā)表于 10-20 13:16

    聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)

    是對(duì)Dubbo的擴(kuò)展機(jī)制有一個(gè)基本的了解。如果對(duì)Java SPI比較了解的同學(xué),可以跳過。Java SPI(Service Provider
    發(fā)表于 06-04 17:33

    嵌入式Linux系統(tǒng)內(nèi)核抽象的動(dòng)態(tài)擴(kuò)展技術(shù)

    能下降。另外,微內(nèi)核與傳統(tǒng)的嵌入式Linux內(nèi)核在結(jié)構(gòu)是完全不同的。在嵌入式Linux,如果采用該技術(shù)來增加系統(tǒng)的動(dòng)態(tài)擴(kuò)展性能,需要對(duì)內(nèi)核結(jié)構(gòu)重新設(shè)計(jì)。  (2)可
    發(fā)表于 10-26 09:22

    嵌入式Linux系統(tǒng)內(nèi)核抽象的動(dòng)態(tài)擴(kuò)展技術(shù)

    能下降。另外,微內(nèi)核與傳統(tǒng)的嵌入式Linux內(nèi)核在結(jié)構(gòu)是完全不同的。在嵌入式Linux,如果采用該技術(shù)來增加系統(tǒng)的動(dòng)態(tài)擴(kuò)展性能,需要對(duì)內(nèi)核結(jié)構(gòu)重新設(shè)計(jì)?! ?2)可
    發(fā)表于 10-28 09:53

    嵌入式Linux系統(tǒng)內(nèi)核抽象的動(dòng)態(tài)擴(kuò)展技術(shù)

    的切換和自陷次數(shù)增加,導(dǎo)致系統(tǒng)負(fù)載增加,系統(tǒng)性能下降。另外,微內(nèi)核與傳統(tǒng)的嵌入式Linux內(nèi)核在結(jié)構(gòu)是完全不同的。在嵌入式Linux,如果采用該技術(shù)來增加系統(tǒng)的動(dòng)態(tài)擴(kuò)展性能,需要對(duì)
    發(fā)表于 04-04 17:12

    java動(dòng)態(tài)代理機(jī)制和作用

    的我們的功能,我們更需要學(xué)習(xí)的是其底層是怎么樣的一個(gè)原理,而AOP的原理就是java動(dòng)態(tài)代理機(jī)制,所以本篇隨筆就是對(duì)java動(dòng)態(tài)機(jī)制進(jìn)行一個(gè)回顧。 在
    發(fā)表于 09-27 14:37 ?0次下載

    java動(dòng)態(tài)代理分析

    定義:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。 動(dòng)態(tài)代理使用 java動(dòng)態(tài)代理機(jī)制以巧妙的方式實(shí)現(xiàn)了代理模式的設(shè)計(jì)理念。 代理模式示例代碼 publicinterfaceSubject
    發(fā)表于 09-27 15:14 ?0次下載

    英創(chuàng)信息技術(shù)JAVA操作英創(chuàng)主板SPI接口簡(jiǎn)介

    2017年9月,英創(chuàng)在Linux的文件系統(tǒng)移植了針對(duì)嵌入式Linux的JRE(Java Runtime Environment),能夠支持Java應(yīng)用程序的運(yùn)行。由于Java語(yǔ)言不能
    的頭像 發(fā)表于 02-06 11:09 ?1834次閱讀
    英創(chuàng)信息技術(shù)<b class='flag-5'>JAVA</b>操作英創(chuàng)主板<b class='flag-5'>SPI</b>接口簡(jiǎn)介

    Java實(shí)驗(yàn):類和對(duì)象的擴(kuò)展

    Java實(shí)驗(yàn):類和對(duì)象的擴(kuò)展
    發(fā)表于 07-08 15:36 ?20次下載
    <b class='flag-5'>Java</b>實(shí)驗(yàn):類和對(duì)象的<b class='flag-5'>擴(kuò)展</b>

    源碼級(jí)深度理解Java SPI

    SPI 配置:Java SPI 機(jī)制約定的配置文件,提供查找服務(wù)實(shí)現(xiàn)類的邏輯。配置文件必須置于 META-INF/services 目錄,并且,文件名應(yīng)與服務(wù)提供者接口的完全限定名保
    的頭像 發(fā)表于 11-15 11:38 ?622次閱讀

    基于spring的SPI擴(kuò)展機(jī)制是如何實(shí)現(xiàn)的?

    基本,你一說是基于 spring 的 SPI 擴(kuò)展機(jī)制,再把spring.factories文件和EnableAutoConfiguration提一下,那么這個(gè)問題就答的八九不離十了。
    的頭像 發(fā)表于 03-07 09:17 ?976次閱讀

    JavaSPI動(dòng)態(tài)擴(kuò)展(下)

    基本,你一說是基于spring的SPI擴(kuò)展機(jī)制,再把`spring.factories`文件和`EnableAutoConfiguration`提一下,那么這個(gè)問題就答的八九不離十了。
    的頭像 發(fā)表于 03-24 14:27 ?520次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>中</b>的<b class='flag-5'>SPI</b><b class='flag-5'>動(dòng)態(tài)</b><b class='flag-5'>擴(kuò)展</b>(下)

    如何保證Java程序內(nèi)存密碼的安全

    開發(fā)和構(gòu)建簡(jiǎn)單?;?SPI 的純 Java 編程模型,一鍵式構(gòu)建,將 Java 機(jī)密計(jì)算開發(fā)構(gòu)建門檻一降到底。
    發(fā)表于 04-20 12:49 ?882次閱讀

    SPI是什么?Java SPI的使用介紹

    SPI 全稱 Service Provider Interface,是 Java 提供的一套用來被第三方實(shí)現(xiàn)或者擴(kuò)展的 API,它可以用來啟用框架擴(kuò)展和替換組件。
    的頭像 發(fā)表于 09-02 09:58 ?1307次閱讀
    <b class='flag-5'>SPI</b>是什么?<b class='flag-5'>Java</b> <b class='flag-5'>SPI</b>的使用介紹

    java本身自帶的SPI擴(kuò)展機(jī)制是怎么一回事?

    八股文背多了,相信大家都聽說過一個(gè)詞,SPI 擴(kuò)展
    的頭像 發(fā)表于 01-02 10:32 ?621次閱讀
    <b class='flag-5'>java</b>本身自帶的<b class='flag-5'>SPI</b><b class='flag-5'>擴(kuò)展</b>機(jī)制是怎么一回事?