1. 深入剖析 Spring Boot 的 SPI 機(jī)制

        共 6651字,需瀏覽 14分鐘

         ·

        2024-07-26 15:24

        ?? 歡迎加入小哈的星球,你將獲得: 專屬的項(xiàng)目實(shí)戰(zhàn) / 1v1 提問 / Java 學(xué)習(xí)路線 / 學(xué)習(xí)打卡 / 每月贈(zèng)書 / 社群討論

        • 新項(xiàng)目:《從零手?jǐn)]:仿小紅書(微服務(wù)架構(gòu))》 正在持續(xù)爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 點(diǎn)擊查看項(xiàng)目介紹;
        • 《從零手?jǐn)]:前后端分離博客項(xiàng)目(全棧開發(fā))》 2期已完結(jié),演示鏈接:http://116.62.199.48/;

        截止目前,累計(jì)輸出 50w+ 字,講解圖 2200+ 張,還在持續(xù)爆肝中.. 后續(xù)還會(huì)上新更多項(xiàng)目,目標(biāo)是將 Java 領(lǐng)域典型的項(xiàng)目都整一波,如秒殺系統(tǒng), 在線商城, IM 即時(shí)通訊,Spring Cloud Alibaba 等等,戳我加入學(xué)習(xí),解鎖全部項(xiàng)目,已有1800+小伙伴加入


        SPI(Service Provider Interface)是JDK內(nèi)置的一種服務(wù)提供發(fā)現(xiàn)機(jī)制,可以用來啟用框架擴(kuò)展和替換組件,主要用于框架中開發(fā),例如Dubbo、Spring、Common-Logging,JDBC等采用采用SPI機(jī)制,針對同一接口采用不同的實(shí)現(xiàn)提供給不同的用戶,從而提高了框架的擴(kuò)展性。

        Java SPI實(shí)現(xiàn)

        Java內(nèi)置的SPI通過java.util.ServiceLoader類解析classPath和jar包的META-INF/services/目錄 下的以接口全限定名命名的文件,并加載該文件中指定的接口實(shí)現(xiàn)類,以此完成調(diào)用。

        示例說明

        創(chuàng)建動(dòng)態(tài)接口

        public interface VedioSPI
        {
            void call();
        }

        實(shí)現(xiàn)類1

        public class Mp3Vedio implements VedioSPI
        {
            @Override
            public void call()
            {
                System.out.println("this is mp3 call");
            }

        }

        實(shí)現(xiàn)類2

        public class Mp4Vedio implements VedioSPI
        {
            @Override
            public void call()
            {
               System.out.println("this is mp4 call");
            }

        }

        在項(xiàng)目的source目錄下新建META-INF/services/目錄下,創(chuàng)建com.skywares.fw.juc.spi.VedioSPI文件。

        圖片

        相關(guān)測試

        public class VedioSPITest
        {
            public static void main(String[] args)
            {
                ServiceLoader<VedioSPI> serviceLoader =ServiceLoader.load(VedioSPI.class);
                
                serviceLoader.forEach(t->{
                    t.call();
                });
            }
        }

        說明:Java實(shí)現(xiàn)spi是通過ServiceLoader來查找服務(wù)提供的工具類。

        運(yùn)行結(jié)果:

        圖片

        源碼分析

        上述只是通過簡單的示例來實(shí)現(xiàn)下java的內(nèi)置的SPI功能。其實(shí)現(xiàn)原理是ServiceLoader是Java內(nèi)置的用于查找服務(wù)提供接口的工具類,通過調(diào)用load()方法實(shí)現(xiàn)對服務(wù)提供接口的查找,最后遍歷來逐個(gè)訪問服務(wù)提供接口的實(shí)現(xiàn)類。

        圖片

        從源碼可以發(fā)現(xiàn):

        • ServiceLoader類本身實(shí)現(xiàn)了Iterable接口并實(shí)現(xiàn)了其中的iterator方法,iterator方法的實(shí)現(xiàn)中調(diào)用了LazyIterator這個(gè)內(nèi)部類中的方法,迭代器創(chuàng)建實(shí)例。
        • 所有服務(wù)提供接口的對應(yīng)文件都是放置在META-INF/services/目錄下,final類型決定了PREFIX目錄不可變更。

        雖然java提供的SPI機(jī)制的思想非常好,但是也存在相應(yīng)的弊端。具體如下:

        • Java內(nèi)置的方法方式只能通過遍歷來獲取
        • 服務(wù)提供接口必須放到META-INF/services/目錄下。

        針對java的spi存在的問題,Spring的SPI機(jī)制沿用的SPI的思想,但對其進(jìn)行擴(kuò)展和優(yōu)化。

        Spring SPI

        Spring SPI沿用了Java SPI的設(shè)計(jì)思想,Spring采用的是spring.factories方式實(shí)現(xiàn)SPI機(jī)制,可以在不修改Spring源碼的前提下,提供Spring框架的擴(kuò)展性。

        Spring 示例

        定義接口

        public interface DataBaseSPI
        {
           void getConnection();
        }

        相關(guān)實(shí)現(xiàn)

        ##DB2實(shí)現(xiàn)
        public class DB2DataBase implements DataBaseSPI
        {
            @Override
            public void getConnection()
            {
                System.out.println("this database is db2");
            }

        }

        ##Mysql實(shí)現(xiàn)
        public class MysqlDataBase implements DataBaseSPI
        {
            @Override
            public void getConnection()
            {
               System.out.println("this is mysql database");
            }

        }

        1、在項(xiàng)目的META-INF目錄下,新增spring.factories文件

        圖片

        2、填寫相關(guān)的接口信息,內(nèi)容如下:

        com.skywares.fw.juc.springspi.DataBaseSPI = com.skywares.fw.juc.springspi.DB2DataBase, com.skywares.fw.juc.springspi.MysqlDataBase

        說明多個(gè)實(shí)現(xiàn)采用逗號(hào)分隔。

        相關(guān)測試類

        public class SpringSPITest
        {
            public static void main(String[] args)
            {
                 List<DataBaseSPI> dataBaseSPIs =SpringFactoriesLoader.loadFactories(DataBaseSPI.class, 
                         Thread.currentThread().getContextClassLoader());
                 
                 for(DataBaseSPI datBaseSPI:dataBaseSPIs){
                    datBaseSPI.getConnection();
                 }
            }
        }

        輸出結(jié)果

        圖片

        從示例中我們看出,Spring 采用spring.factories實(shí)現(xiàn)SPI與java實(shí)現(xiàn)SPI非常相似,但是spring的spi方式針對java的spi進(jìn)行的相關(guān)優(yōu)化具體內(nèi)容如下:

        • Java SPI是一個(gè)服務(wù)提供接口對應(yīng)一個(gè)配置文件,配置文件中存放當(dāng)前接口的所有實(shí)現(xiàn)類,多個(gè)服務(wù)提供接口對應(yīng)多個(gè)配置文件,所有配置都在services目錄下;
        • Spring factories SPI是一個(gè)spring.factories配置文件存放多個(gè)接口及對應(yīng)的實(shí)現(xiàn)類,以接口全限定名作為key,實(shí)現(xiàn)類作為value來配置,多個(gè)實(shí)現(xiàn)類用逗號(hào)隔開,僅spring.factories一個(gè)配置文件。

        那么spring是如何通過加載spring.factories來實(shí)現(xiàn)SpI的呢?我們可以通過源碼來進(jìn)一步分析。

        源碼分析

        圖片

        說明:loadFactoryNames解析spring.factories文件中指定接口的實(shí)現(xiàn)類的全限定名,具體實(shí)現(xiàn)如下:

        圖片

        說明:獲取所有jar包中META-INF/spring.factories文件路徑,以枚舉值返回。遍歷spring.factories文件路徑,逐個(gè)加載解析,整合factoryClass類型的實(shí)現(xiàn)類名稱,獲取到實(shí)現(xiàn)類的全類名稱后進(jìn)行類的實(shí)例話操作,其相關(guān)源碼如下:

        圖片

        說明:實(shí)例化是通過反射來實(shí)現(xiàn)對應(yīng)的初始化。

        ?? 歡迎加入小哈的星球,你將獲得: 專屬的項(xiàng)目實(shí)戰(zhàn) / 1v1 提問 / Java 學(xué)習(xí)路線 / 學(xué)習(xí)打卡 / 每月贈(zèng)書 / 社群討論

        • 新項(xiàng)目:《從零手?jǐn)]:仿小紅書(微服務(wù)架構(gòu))》 正在持續(xù)爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 點(diǎn)擊查看項(xiàng)目介紹;
        • 《從零手?jǐn)]:前后端分離博客項(xiàng)目(全棧開發(fā))》 2期已完結(jié),演示鏈接:http://116.62.199.48/;

        截止目前,累計(jì)輸出 50w+ 字,講解圖 2200+ 張,還在持續(xù)爆肝中.. 后續(xù)還會(huì)上新更多項(xiàng)目,目標(biāo)是將 Java 領(lǐng)域典型的項(xiàng)目都整一波,如秒殺系統(tǒng), 在線商城, IM 即時(shí)通訊,Spring Cloud Alibaba 等等,戳我加入學(xué)習(xí),解鎖全部項(xiàng)目,已有1800+小伙伴加入


            
               

        1. 我的私密學(xué)習(xí)小圈子~

        2. 自從用了CheckStyle插件,代碼寫的越來越規(guī)范了....

        3. 史上最全 Git 圖文教程,沒有之一

        4. 偷偷曝光下國內(nèi)軟件外包公司?。?024 最新版,很全?。?/a>

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過內(nèi)容,記得讀完點(diǎn)一下在看,加個(gè)星標(biāo),這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。

        點(diǎn)“在看”支持小哈呀,謝謝啦

        瀏覽 183
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 99精品成人在线视频 | 色九九在线视频精品99 | 人人操人人插人人摸 | 五月婷婷精品 | 男女拍拍拍拍 |