日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

某厂面试:如何优雅使用 SPI 机制

發(fā)布時間:2025/3/16 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 某厂面试:如何优雅使用 SPI 机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

代碼不多,文章可能有點長。朋友面試某廠問到的 SPI 機制,聯(lián)想到自己項目最近寫到的 SPI 場景,文章簡要描述下 SPI 機制的發(fā)展歷程

?

產(chǎn)出背景

因為最近項目中使用分庫分表以及數(shù)據(jù)加密使用到了 ShardingSphere,所以決定這段時間看看源碼實現(xiàn)。問我為什么要讀源碼?不看源碼怎么提高逼格嘞,就是這么樸實無華~

?

Sharding-Jdbc SPI

看源碼的歷程,往往從點開 Jar 包的瞬間開始。好巧不巧,就看到源代碼包下有個 SPI 包,處于好奇心就點了一點,嗯~ 代碼果然很熟悉,還是那個配方原來的味道

看了許久,陷入深深的沉思。內(nèi)心小九九:這玩意好像之前看過,但是在哪我忘了,這到底是個啥?

代碼還是那個代碼,只是它認(rèn)識我,我不認(rèn)識它了

這一塊的 SPI 接口是 shrding-jdbc 預(yù)留自定義加密器的接口

看到這里相信就遇到過絕大多數(shù)技術(shù)同學(xué)都會遇到的一個問題,那就是 認(rèn)為自己會了,實際情況呢?不一定。所以,學(xué)習(xí)一門技術(shù),一定要多看幾遍,嘗試去理解記憶。千萬不要看一遍之后,眼高手低認(rèn)為技術(shù) so easy,然后隔十天半個月就啥都不記的

繼續(xù)回過頭來說說今天的主角:SPI。首先回答這么一個問題,什么是 SPI 機制

SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機制。為了被第三方實現(xiàn)或擴展的 API,它可以用于實現(xiàn)框架擴展或組件替換

SPI 機制本質(zhì)是將 接口實現(xiàn)類的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件,加載文件中的實現(xiàn)類,這樣運行時可以動態(tài)的為接口替換實現(xiàn)類

看文字描述介紹總是枯燥無味且空洞的。簡單一點來說,就是你在 META-INF/services 下面定義個文件,然后通過一個特殊的類加載器,啟動的時候加載你定義文件中的類,這樣就能擴展原有框架的功能

就這么簡單,那可能有讀者會問:我不定義在 META-INF/services 下面行不行?就想定義在別的地方

不行滴,請遏制住這么危險的想法,人家怎么定義你就怎么實現(xiàn)。這是 JDK 規(guī)定好的配置路徑,你隨便定義,類加載器怎么知道去哪里加載

看到這個 PREFIX 常量之后,想法比較活躍的小伙子不知道清醒點了么。簡單畫張圖來描述下 SPI 的運行機制

有點 SPI 基礎(chǔ)的同學(xué)看到圖之后應(yīng)該又開始自信了,這不就是我之前看過的那玩意么?是的,技術(shù)還是那個技術(shù),可以繼續(xù)往下看看,有沒有自己不知道的

?

為什么要有 SPI

了解一項技術(shù)的前提,一定要知道它為了解決什么樣的痛點而存在,JDK 作者也不會沒屁事加點代碼玩

引入了 SPI 機制后,服務(wù)接口與服務(wù)實現(xiàn)就會達(dá)成分離的狀態(tài),可以實現(xiàn) 解耦以及程序可擴展機制。服務(wù)提供者(比如 springboot starter)提供出 SPI 接口后,客戶端(平常的 springboot 項目)就可以通過本地注冊的形式,將實現(xiàn)類注冊到服務(wù)端,輕松實現(xiàn)可插拔

數(shù)據(jù)加密舉例

以實際項目舉個例子,就拿 sharding-jdbc 數(shù)據(jù)加密模塊來說,sharding-jdbc 本身支持 AES 和 MD5 兩種加密方式。但是,如果客戶端不想用內(nèi)置的兩種加密,偏偏想用 RSA 算法呢?難道每加一種算法,sharding-jdbc 就要發(fā)個版本么

sharding-jdbc 可不會這么干,首先提供出 Encryptor 加密接口,并引入 SPI 的機制,做到服務(wù)接口與服務(wù)實現(xiàn)分離的效果。如果客戶端想要使用新的加密算法,只需要在客戶端項目 META-INF/services 目錄下定義接口的全限定名稱文件,并在文件內(nèi)寫上加密實現(xiàn)類的全限定名,就像這樣式的

通過 SPI 的方式,就可以將客戶端提供的加密算法加載到 sharding-jdbc 加密規(guī)則中,這樣就可以在項目運行中選擇自定義算法來對數(shù)據(jù)進(jìn)行加密存儲

通過 sharding-jdbc 的例子,可以很好的看出來,上面提到的 SPI 優(yōu)點,都體現(xiàn)了出來

  • 客戶端(自己的項目)提供了服務(wù)端(sharding-jdbc)的接口自定義實現(xiàn),但是與服務(wù)端狀態(tài)分離,只有在客戶端提供了自定義接口實現(xiàn)時才會加載,其它并沒有關(guān)聯(lián);客戶端的新增或刪除實現(xiàn)類不會影響服務(wù)端

  • 如果客戶端不想要 RSA 算法,又想要使用內(nèi)置的 AES 算法,那么可以隨時刪掉實現(xiàn)類,可擴展性強,插件化架構(gòu)

  • 配合實際案例理解 SPI 是不是很簡單。為了防止有些小伙伴沒有理解 sharding-jdbc 的例子,這里再舉一個真實的例子

    對象存儲舉例

    假如你是一家集團(tuán)公司里做公共架構(gòu)開發(fā)的(可以把這個集團(tuán)想大一點,幾百家子公司的那種 ????? ),領(lǐng)導(dǎo)給你安排了個開發(fā)任務(wù),需要你開發(fā)一個對象存儲服務(wù),讓其它業(yè)務(wù)線的團(tuán)隊使用,統(tǒng)一集團(tuán)內(nèi)部的對象存儲

    OK,開發(fā)訴求明白了,這個時候就該想想怎么去完成這個需求(主要想給領(lǐng)導(dǎo)留個好印象,升官發(fā)財 ing...)。首先應(yīng)該考慮的是要兼容多套對象存儲供應(yīng)商,比如阿里 OSS、騰訊 COS、華為云 OBS,最基本的三連對吧

    高高興興的封裝了個 starter,告訴領(lǐng)導(dǎo)封裝完成了,然后就下發(fā)到各項目組去用了。但是這個時候其中一個子公司負(fù)責(zé)人告訴你,說他們之前用的七牛云 Kodo

    心態(tài)炸了呀,難道要給他再適配一個七牛云么?萬一適配完這個,又一位大哥說項目自建 HDFS 咋整

    聊到這,大家就明白了吧,SPI 的場景可不就出現(xiàn)了么。就是身為服務(wù)提供者,在你無法形成絕對規(guī)范強制的時候,"放權(quán)" 往往是比較明智的選擇,適當(dāng)讓客戶端去自定義實現(xiàn)

    這個時候,回過頭想一想最初的一個問題。為什么 sharding-jdbc 不多實現(xiàn)幾套算法,而是提供出一個 SPI 接口呢

    因為開發(fā)者明白,不論提供多少接口,總有個別用戶因各方面因素導(dǎo)致的個性化需求。個性化這個事情是追摸不透的,就像 女生的心思一樣,永遠(yuǎn)不知道在想什么...(重點都加黑加粗了,剩下的全靠自己領(lǐng)悟)

    ?

    實戰(zhàn)講解

    都說到這了,不來個實戰(zhàn),感覺有點說不過去。吹過的牛逼,負(fù)責(zé)到底!就實現(xiàn)上面說的統(tǒng)一對象存儲服務(wù)的代碼

    最簡單的對象存儲,只需要兩個接口就可以實現(xiàn)功能,分別是 上傳和下載

    定義好上傳、下載接口后,我們就要考慮,如何讓客戶端項目可以選擇底層的對象存儲服務(wù)器,以及如何通過 SPI 的方式將客戶端自定義的文件存儲組件加載到服務(wù)端

    我們可以定義個對象存儲容器,存放可以使用的對象存儲服務(wù),然后再 使用 SPI 的機制加載客戶端自定義組件放到容器。對象存儲服務(wù)放到容器中自然需要一個標(biāo)識,那么就需要給文件接口加一個獲取類型接口

    定義好了接口,就要寫具體的代碼了。我們?yōu)?對象存儲服務(wù)提供出一個對外的門面,所有訪問對象存儲的服務(wù),必須訪問門面對象進(jìn)行文件的上傳下載操作

    下面這段代碼將 對象服務(wù) bean 存儲至容器,并提供根據(jù)客戶端的自定義配置,選擇合適的對象存儲服務(wù)

    代碼里用到的關(guān)鍵字 var 是 lombok 的注解,可以自動識別對象類型

    因為是個示例 demo,所以將獲取對象存儲和具體的上傳、下載耦合在了一起,如果小伙伴有類似需求,一定要將不同行為拆分開,類職責(zé)盡量單一些

    這段代碼整體邏輯不算復(fù)雜,所以也有點自信回頭,就沒跑單元測試,不過問題應(yīng)該不大。解釋一下其中具體邏輯:

  • FileServiceFactory 大家可以理解為文件服務(wù)對外的統(tǒng)一訪問入口。實現(xiàn)了 spirng 初始化的一個接口,可以在 bean 初始化時進(jìn)行代碼邏輯操作

  • bean 初始化時,通過 ServiceLoader 類加載器負(fù)責(zé)加載對象存儲接口,這樣就能加載到客戶端存放到 META-INF/services 中的自定義對象存儲實現(xiàn)

  • 獲取到自定義對象存儲后,和服務(wù)端本身自帶的對象存儲一起存放至容器中,這樣就可以根據(jù)項目中的 fileStoreType 獲取對應(yīng)的服務(wù)了

  • 結(jié)合實際的項目場景,一個簡簡單單的 SPI 應(yīng)用就完成了,自我感覺比 JDBC 裝配的例子更好理解一些

    上面的業(yè)務(wù)只是為了讓不理解 SPI 的小伙伴更好的掌握應(yīng)用場景,其實對象存儲服務(wù)是一種可窮舉的業(yè)務(wù)場景,SPI 并不是唯一的解決思路。當(dāng)然,為了省事使用 SPI 也沒啥問題。最后提一句,SPI 最合適的還是沒有統(tǒng)一業(yè)務(wù)實現(xiàn)場景,就像上面提到過的加密算法

    ?

    深入解析 SPI

    一篇技術(shù)解析文章,適當(dāng)放一些源碼解析感覺會更好一些。下面一起來看看 ServiceLoader 底層都做了什么事情

    通過 ServiceLoader 的 load 方法創(chuàng)建一個新的 ServiceLoader,并實例化其中的成員變量

    應(yīng)用程序通過迭代器接口獲取對象實例,這里首先會判斷 providers 對象中是否有實例對象

    如果有實例,那么就返回;如果沒有,執(zhí)行類的裝載步驟,具體類裝載實現(xiàn)如下:

  • LazyIterator#hasNextService 讀取 META-INF/services 下的配置文件,獲得所有能被實例化的類的名稱,并完成 SPI 配置文件的解析

  • LazyIterator#nextService 負(fù)責(zé)實例化 hasNextService() 讀到的實現(xiàn)類,并將實例化后的對象存放到 providers 集合中緩存

  • 如果你不知道上面的一些 "黑話" 不要緊,因為都是 ServiceLoader 底層執(zhí)行的方法,跟著下面這個程序敲一遍代碼就懂了

    這里為了跟源碼,也是把上面對象存儲的邏輯,簡單寫了個 SPI 示例,證明是沒有問題的。如果小伙伴想真正了解,就需要跟下源碼去看看,其它源碼部分就不細(xì)說了

    ?

    結(jié)言

    上面說了很多關(guān)于 SPI 機制的優(yōu)點以及應(yīng)用場景,這里總結(jié)下關(guān)鍵內(nèi)容

  • SPI 機制優(yōu)勢就是解耦。將接口的定義以及具體業(yè)務(wù)實現(xiàn)分離,而不是和業(yè)務(wù)端全部耦合在一端。可以實現(xiàn) 運行時根據(jù)業(yè)務(wù)實際場景啟用或者替換具體組件

  • SPI 機制的場景就是 沒有統(tǒng)一實現(xiàn)標(biāo)準(zhǔn)的業(yè)務(wù)場景。一般就是,服務(wù)端有標(biāo)準(zhǔn)的接口,但是沒有統(tǒng)一的實現(xiàn),需要業(yè)務(wù)方提供其具體實現(xiàn)。比如說 JDBC 的 java.sql.Driver 接口和不同云廠商提供的數(shù)據(jù)庫實現(xiàn)包

  • 每個事物都是既有優(yōu)點,同時也伴隨著缺點。要從兩個方面去看,不能總盯著一方面。這里說一下 SPI 機制的缺點

  • 不能按需加載。雖然 ServiceLoader 做了延遲加載,但是只能通過遍歷的方式全部獲取。如果其中某些實現(xiàn)類很耗時,而且你也不需要加載它,那么就形成了資源浪費

  • 獲取某個實現(xiàn)類的方式不夠靈活,只能通過迭代器的形式獲取。這兩點可以參考 Dubbo SPI 實現(xiàn)方式進(jìn)行業(yè)務(wù)優(yōu)化

  • 文章通過圖文并茂的方式幫助大家重新梳理了一遍 SPI 的場景、優(yōu)勢和缺點,看完文章后相信大家對 SPI 機制有了更深入的認(rèn)識

    梳理出 SPI 的場景以及優(yōu)勢后,小伙伴最好再去 Debug 源代碼,這樣會大家對 SPI 的實現(xiàn)才能更加清楚。只有對一個知識點真正掌握,才不至于事后很快遺忘

    另外可以通過項目中的場景,比如文中提到的加密、對象存儲,通過類比的方式結(jié)合項目邏輯去實現(xiàn)代碼代入,這樣能夠更好的去學(xué)習(xí)以及擴展相關(guān)的設(shè)計思路

    有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

    歡迎大家關(guān)注Java之道公眾號

    好文章,我在看??

    總結(jié)

    以上是生活随笔為你收集整理的某厂面试:如何优雅使用 SPI 机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 后入内射欧美99二区视频 | av三级网| www.日韩视频 | 欧美亚洲国产精品 | 色婷婷九月 | 黄色片不卡 | 少妇免费毛片久久久久久久久 | 日韩亚洲天堂 | 国产高清无遮挡 | 99热精品在线 | 午夜精品久久久久久久99热浪潮 | 波多野吉衣在线观看视频 | 免费观看成人毛片 | 爱草在线视频 | 中文字幕亚洲精品在线 | 欧美日韩一区二区三区在线电影 | 国产精品久久色 | 国内露脸中年夫妇交换 | 亚洲精品视频久久久 | 电影《两个尼姑》免费播放 | 亚洲天堂日韩在线 | 欧美a网| 偷拍精品一区二区三区 | 欧美日韩精品在线播放 | 色就是色综合 | 日本一级免费视频 | 少妇精品视频 | 韩国伦理片在线观看 | 日韩精品一区二区三区在线视频 | 蜜桃成熟时李丽珍在线观看 | 精品在线一区二区三区 | 人妻丰满熟妇岳av无码区hd | 亚洲人在线观看视频 | 日本精品视频在线 | 在线午夜电影 | 插插影视 | 国产91精品露脸国语对白 | 涩涩涩涩涩涩涩涩涩 | av十大美巨乳| 日韩精品在线观看一区二区三区 | 污污污污污污www网站免费 | 日本欧美亚洲 | 操一操| 人妻无码一区二区三区免费 | 亚洲精品女人 | 中文字幕偷拍 | 国产免费一区二区三区在线观看 | www.蜜桃av| 在线免费观看你懂的 | 国产又粗又猛又黄又爽无遮挡 | 国产精品久久久久久久久久小说 | 国产日韩欧美综合在线 | 成人av无码一区二区三区 | 婷婷俺去也 | 狠狠干伊人网 | av青青 | 午夜久久网站 | 亚洲三级免费观看 | 午夜看片网站 | 69堂在线观看 | 亚洲自偷自偷偷色无码中文 | 艹少妇视频 | 男人天堂新地址 | 婷婷深爱| 欧美自拍第一页 | 成人性生交大片免费看中文 | 成人人人人人欧美片做爰 | 日本一区中文字幕 | 久操影视 | 午夜寂寞影院在线观看 | 久久久久久久久久久久久女过产乱 | 国产精品色在线 | 综合色影院| 欧美顶级metart裸体全部自慰 | 国产一区二区三区四区视频 | 九九九九九伊人 | 久久久精品美女 | 亚洲播播 | 亚洲一区二区视频在线播放 | 2022精品国偷自产免费观看 | 极品少妇在线 | 欧美日韩色视频 | 欧美一级黄色片网站 | 黄色av小说在线观看 | 成人123区| 国产婷婷一区二区三区久久 | 亚洲精品视频一区二区 | 加勒比在线一区 | 男人操女人的软件 | 国产二区精品 | 老熟妇毛片 | 亚州av在线 | 欧美黑人疯狂性受xxxxx野外 | 国产亚洲美女精品久久久2020 | 欧美巨大乳 | 四川丰满少妇被弄到高潮 | 高潮毛片无遮挡免费看 | 玖玖在线观看 | 视频一区二区在线观看 |