Dubbo 是基於 Java 原生 SPI 機制思想的一個改進,因此,先從 JAVA SPI 機制開始瞭解什麼是 SPI 之後再去學習Dubbo 的 SPI,就比較容易了java
什麼是JDK的SPI?mysql
SPI 全稱( service provider interface ),是 JDK 內置的一種服務提供發現機制,目前市面上有不少框架都是用它來作服務的擴展發現,你們耳熟能詳的如 JDBC、日誌框架都有用到;簡單來講,它是一種動態替換髮現的機制。舉個簡單的例子,若是咱們定義了一個規範,須要第三方廠商去實現,那麼對於咱們應用方來講,只須要集成對應廠商的插件,既能夠完成對應規範的實現機制。 造成一種插拔式的擴展手段spring
SPI 規範總結sql
實現 SPI,就須要按照 SPI 自己定義的規範來進行配置,SPI規範以下數據庫
1. 須要在classpath下建立一個目錄,該目錄命名必須是:META-INF/servicesapi
2. 在該目錄下建立一個 properties 文件,該文件須要知足oracle
如下幾個條件app
a) 文件名必須是擴展的接口的全路徑名稱框架
b) 文件內部描述的是該擴展接口的全部實現類ide
c) 文件的編碼格式是 UTF-8
3. 經過 java.util.ServiceLoader 的加載機制來發現
真實應用場景
SPI 在 很 多 地 方 有 應 用 , 大 家 可 以 看 看 最 常 用 的java.sql.Driver 驅動。JDK 官方提供了 java.sql.Driver 這個驅動擴展點,可是大家並無看到 JDK 中有對應的 Driver實現。 那在哪裏實現呢?以鏈接 Mysql 爲例,咱們須要添加 mysql-connector-java依賴。而後,大家能夠在這個jar包中找到SPI的配置信息。以下圖,因此 java.sql.Driver 由各個數據庫廠商自行實現。這就是 SPI 的實際應用。固然除了這個意外,你們在 spring的包中也能夠看到相應的痕跡
按照一樣思路可實現啊:
好比說咱們鏈接數據,DataSource定義了規範,而後Mysql和oracle本身實現規範,最後咱們要選哪一最後做爲咱們的規範,徹底是由我們本身來決定。
以下圖所示:
JDK SPI缺點:
1. JDK標準的SPI會一次性加載實例化擴展點的全部實現,什麼意思呢?就是若是你在 META-INF/service 下的文件裏面加了 N 個實現類,那麼 JDK 啓動的時候都會一次性所有加載。那麼若是有的擴展點實現初始化很耗時或者若是作技術人的之路明燈,作職場生涯的精神導師有些實現類並無用到,那麼會很浪費資源
2. 若是擴展點加載失敗,會致使調用方報錯,並且這個錯誤很難定位到是這個緣由
新建項目spi-demo,同時建立module:api,mysql,oracle,demo
api
package com.tian; public interface DataSource { String connect(String msg); }
mysql
package com.tian.mysql; import com.tian.DataSource; public class MysqlDataSource implements DataSource { @Override public String connect(String msg) { System.out.println("mysql"); return null; } }
oracle
package com.tian.oracle; import com.tian.DataSource; public class OraclelDataSource implements DataSource { @Override public String connect(String msg) { System.out.println("oracle"); return null; } }
demo
這裏是把兩種都加載進來了,
package com.tian; import java.util.ServiceLoader; public class DataSourceFactory { public DataSourceFactory() { } public static void getDataSource() { ServiceLoader<DataSource> serviceLoader = ServiceLoader.load(DataSource.class); for (DataSource dataSource : serviceLoader) { dataSource.connect("1111"); } } }
package com.tian; public class DemoMain { public static void main(String[] args) { DataSourceFactory.getDataSource(); } }
運行Demo輸出
若是咱們只在demo中pom.xml中導入mysql.jar。
再次運行Demo。那麼最後輸出:
自此我們已經實現了JDK的SPI。後面Dubbo源碼裏面大量使用SPI機制(Dubbo中是JDK-SPI的升級版本)