1、平時遇到過的使用java的spi的例子
1)mysql的驅動
2)spring-web
2、spi的設計目標
面向對象的設計裏,模塊之間是接口編程,模塊之間不對實現類進行硬編碼,如果實現類寫死在代碼裏,想要換一種實現,就需要修改代碼,爲了不在代碼裏寫死,就需要一種服務的發現機制,爲某個接口尋找服務實現的機制,有點類似ioc,將裝配的控制權移交到代碼之外
3、spi的約定
當一個接口有多個實現類的時候,一般在META-INF/services/目錄下,創建接口的同名文件(接口的包名+文件名)
文件的內容就是接口的實現類的名稱(包名+文件名)
而當外部程序裝配這個模塊的時候,就能通過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成模塊的注入。 基於這樣一個約定就能很好的找到服務接口的實現類,而不需要再代碼裏制定。jdk提供服務實現查找的一個工具類java.util.ServiceLoader
4、查找接口的實現通過ServiceLoader來完成
Iterator<UserService> services = ServiceLoader.load(UserService.class).iterator();
5、dubbo爲什麼要實現自己的spi,而不是用jdk的spi
1)jdk的spi會一次性實例化一個擴展點的所有實現,初始化會很耗時間,並且沒有用到的實現也會加載,浪費資源
2)增加了對擴展點ioc和aop的支持,一個擴展點可以直接setter注入其他擴展點
6、dubbo的spi的約定
dubbo spi 在JAVA自帶的SPI基礎上加入了擴展點的功能,即每個實現類都會對應至一個擴展點名稱,其目的是 應用可基於此名稱進行相應的裝配。這樣就解決了jdk加載全部的實現類的缺點了。
dubbo spi 目錄文件
dubbo spi 文件內容:
wanglu=wanglu.dubbo.server.WlFilter
裝配自定義Filter
<dubbo:provider filter="wanglu" timeout="2000" retries="2" id="abc"></dubbo:provider>
7、dubbo的spi的源碼解析
1)dubbo spi的目的:dubbo獲取一個實現類的對象
2)通過ExtensionLoader實現spi擴展點的加載
途徑:public T getExtension(String name)
實現途徑:
getExtensionLoader(Class<T> type),作用就是爲該Class<T>接口new一個ExtensionLoader,然後緩存起來。
getAdaptiveExtension() 獲取一個擴展裝飾類的對象,這個類有一個規則,如果他沒有@Adaptive註解,就動態創建一個裝飾類,例如: Protocol$Adaptive對象
getExtension(String name)獲取一個對象
3)源碼
---------------------------------------------------ExtensionLoader.getExtensionLoader(Class<T> type)
ExtensionLoader.getExtensionLoader(Container.class)
-->this.type = type;
-->objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-->this.type = type;
-->objectFactory = null;
執行以上的代碼,完成了兩個屬性的初始化
1、每個ExtensionLoader都包含兩個值type和objectFactory
<T> type //構造器初始化要得到的接口名
ExtensionFactory objectFactory 構造器,初始化時AdaptiveExtensionFactory【SpiExtensionFactory】
2、new 一個ExtensionLoader都存儲在ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS
3、關於objectFactory的一些細節
objectFactory 就是ExtensionFactory 通過ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()來實現的,但是objectFactory 爲空
objectFactory就是dubbo的IOC提供所有對象的