<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java SPI 與 Dubbo SPI 有什么區(qū)別?

          共 4510字,需瀏覽 10分鐘

           ·

          2021-06-08 09:12

          點擊上方藍色“小哈學(xué)Java”,選擇“設(shè)為星標(biāo)

          回復(fù)“資源”獲取獨家整理的學(xué)習(xí)資料!


          作者:廢物大師兄
          來源:www.cnblogs.com/cjsblog/p/14346766.html

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

          在Java中SPI是被用來設(shè)計給服務(wù)提供商做插件使用的。基于策略模式來實現(xiàn)動態(tài)加載的機制。我們在程序只定義一個接口,具體的實現(xiàn)交個不同的服務(wù)提供者;在程序啟動的時候,讀取配置文件,由配置確定要調(diào)用哪一個實現(xiàn)。有很多組件的實現(xiàn),如日志、數(shù)據(jù)庫訪問等都是采用這樣的方式,最常用的就是 JDBC 驅(qū)動。

          1、Java SPI

          核心類:java.util.ServiceLoader

          服務(wù)是一組眾所周知的接口和(通常是抽象的)類。服務(wù)提供者是服務(wù)的特定實現(xiàn)。提供者中的類通常實現(xiàn)接口,并子類化服務(wù)本身中定義的類。服務(wù)提供者可以以擴展的形式安裝在Java平臺的實現(xiàn)中,即放置在任何常見擴展目錄中的jar文件。提供程序也可以通過將它們添加到應(yīng)用程序的類路徑或其他特定于平臺的方法來提供。

          通過在資源目錄META-INF/services中放置一個提供程序配置文件來識別服務(wù)提供程序。文件名是服務(wù)類型的完全限定二進制名稱。該文件包含具體提供程序類的完全限定二進制名的列表,每行一個。每個名稱周圍的空格和制表符以及空白行將被忽略。注釋字符是'#';在每一行中,第一個注釋字符之后的所有字符都將被忽略。文件必須用UTF-8編碼。

          按照上面的方法,我們來寫個例子試一下

          首先,定義一個接口Car

          package org.example;

          public interface Car {
              void run();
          }

          兩個實現(xiàn)類

          ToyotaCar.java

          package org.example;

          public class ToyotaCar implements Car {
              @Override
              public void run() {
                  System.out.println("Toyota");
              }
          }

          HondaCar.java

          package org.example;

          public class HondaCar implements Car {
              @Override
              public void run() {
                  System.out.println("Honda");
              }
          }

          在META-INF/services下創(chuàng)建一個名為org.example.Car的文本文件

          org.example.ToyotaCar
          org.example.HondaCar

          最后,寫個測試類運行看一下效果

          package org.example;

          import java.util.ServiceLoader;

          public class App
          {
              public static void main( String[] args )
              {
                  ServiceLoader<Car> serviceLoader = ServiceLoader.load(Car.class);
                  serviceLoader.forEach(x->x.run());
              }
          }

          跟一下ServiceLoader的代碼,看看是怎么找到服務(wù)實現(xiàn)的

          用當(dāng)前線程的類加載器加載

          接口和類加載器都有了,萬事俱備只欠東風(fēng)


          Java SPI 不足之處:

          2、Dubbo SPI

          Dubbo重新實現(xiàn)了一套功能更強的SPI機制, 支持了AOP與依賴注入,并且利用緩存提高加載實現(xiàn)類的性能,同時支持實現(xiàn)類的靈活獲取。

          <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
                <version>2.7.8</version>
          </dependency>

          核心類:org.apache.dubbo.common.extension.ExtensionLoader

          先來了解一下@SPI注解,@SPI是用來標(biāo)記接口是一個可擴展的接口

          改造一下前面的例子,在Car接口上加上@SPI注解

          package org.example;

          import org.apache.dubbo.common.extension.SPI;

          @SPI
          public interface Car {
              void run();
          }

          兩個實現(xiàn)類不變。

          在META-INF/dubbo目錄下創(chuàng)建名為org.example.Car的文本文件,內(nèi)容如下(鍵值對形式):

          toyota=org.example.ToyotaCar
          honda=org.example.HondaCar

          編寫測試類:

          package org.example;

          import org.apache.dubbo.common.extension.ExtensionLoader;

          import java.util.ServiceLoader;

          public class App
          {
              public static void main( String[] args )
              {
                  //  Java SPI
                  ServiceLoader<Car> serviceLoader = ServiceLoader.load(Car.class);
                  serviceLoader.forEach(x->x.run());

                  //  Dubbo SPI
                  ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);
                  Car car = extensionLoader.getExtension("honda");
                  car.run();
              }
          }

          下面跟一下代碼

          如果緩存Map中有,直接返回,沒有則加載完以后放進去

          加載策略到底是怎樣的呢?

          到這里就有點明白了,又看到了熟悉的ServiceLoad.load(),這不是剛才講的Java SPI嘛。

          回到之前策略那個地方,將策略按順序排列,依次遍歷所有的策略來加載。就是在那三個目錄下查找指定的文件,并讀取其中的內(nèi)容

          跟之前的ServiceLoader如出一轍

          遇到@Adaptive標(biāo)注的就緩存起來

          1. Java 程序員常犯的 10 個 SQL 錯誤!

          2. Kafka 的一個陷阱,你可能用錯了

          3. 定時任務(wù)的五種創(chuàng)建方式,你都會么?

          4. 面試官:說一下線程池內(nèi)部工作原理?

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

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

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  粉嫩逼逼| 麻豆传媒视频免费观看网站网址 | 插插视频网站 | 日本女人在线 | 国产免费操逼A片 |