SPI 簡介
SPI 全稱為 (Service Provider Interface) ,是JDK內置的一種服務提供發(fā)現(xiàn)機制桥滨。 目前有不少框架用它來做服務的擴展發(fā)現(xiàn), 簡單來說,它就是一種動態(tài)替換發(fā)現(xiàn)的機制齐媒, 舉個例子來說蒲每, 有個接口,想運行時動態(tài)的給它添加實現(xiàn)喻括,你只需要添加一個實現(xiàn)邀杏,
通過一個簡單例子來說明SPI是如何使用的。 首先通過一張圖來看看唬血,用SPI需要遵循哪些規(guī)范望蜡,因為spi畢竟是JDK的一種標準。
而后拷恨,把新加的實現(xiàn)脖律,描述給JDK知道就行啦(通過改一個文本文件即可)公司內部,目前Dubbo框架就基于SPI機制提供擴展功能腕侄。
我們首先需要一個目錄小泉,META-INF\services 如下,最終的目錄路徑就像這樣:
文件名字為 接口/抽象類: 全名 文件內容: 接口/抽象類 實現(xiàn)類
就像這樣:com.spi.impl.TextHellocom.chaochao.spi.impl.ImageHello
實現(xiàn)類:
最后冕杠,來看看膏孟,如果使用SPI機制,客戶端代碼:
最后的輸出:Text Hello.Image Hello拌汇。
dubbo的擴展機制和java的SPI機制非常相似柒桑,但是又增加了如下功能:
1 可以方便的獲取某一個想要的擴展實現(xiàn),java的SPI機制就沒有提供這樣的功能
2 對于擴展實現(xiàn)IOC依賴注入功能:
舉例來說:接口A噪舀,實現(xiàn)者A1魁淳、A2。接口B与倡,實現(xiàn)者B1界逛、B2。
現(xiàn)在實現(xiàn)者A1含有setB()方法纺座,會自動注入一個接口B的實現(xiàn)者息拜,此時注入B1還是B2呢?都不是净响,而是注入一個動態(tài)生成的接口B的實現(xiàn)者B$Adpative少欺,該實現(xiàn)者能夠根據(jù)參數(shù)的不同,自動引用B1或者B2來完成相應的功能
3 對擴展采用裝飾器模式進行功能增強馋贤,類似AOP實現(xiàn)的功能
以下面的例子為例來分析下:
其中Protocol接口定義如下:
對應的實現(xiàn)者如下:
ExtensionLoader中含有一個靜態(tài)屬性:
ConcurrentMap, ExtensionLoader>EXTENSION_LOADERS = new ConcurrentHashMap, ExtensionLoader>();
用于緩存所有的擴展加載實例赞别,這里加載Protocol.class,就以Protocol.class為key配乓,創(chuàng)建的ExtensionLoader為value存儲到上述EXTENSION_LOADERS中
這里沒有進行任何的加載操作仿滔。
我們來看下惠毁,ExtensionLoader實例是如何來加載Protocol的實現(xiàn)類的:
1 先解析Protocol上的Extension注解的name,存至String cachedDefaultName屬性中,作為默認的實現(xiàn)
2 到類路徑下的加載 META-INF/services/com.alibaba.dubbo.rpc.Protocol文件