0 FBI WARNING
文章異常囉嗦且繞彎。
1 版本
JDK 版本 : Adoptopenjdk 14.0.1
IDE : idea 2020.2
Dubbo 版本 : dubbo 2.7.6
2 Spi 簡介
Dubbo Spi 是 Dubbo 框架擴展性的根本基礎,是基於 jdk spi 的封裝和擴展。
3 Demo
3.1 需要擴展的接口類
import org.apache.dubbo.common.extension.Adaptive;import org.apache.dubbo.common.extension.SPI;@SPI("dubbo") // spi 最主要的註解public interface SpiDemoService { void sayHello(); }
3.2 接口實現類
一號實現類 :
public class SpiDemoOneServiceImpl implements SpiDemoService { @Override public void sayHello() { System.out.println("hello 1"); }}
二號實現類 :
public class SpiDemoTwoServiceImpl implements SpiDemoService { @Override public void sayHello() { System.out.println("hello 2"); }}
測試方法類:
import org.apache.dubbo.common.extension.ExtensionLoader;public class SpiTest { public static void main(String[] args) { // 獲取 loader 工廠類 ExtensionLoader<SpiDemoService> loader = ExtensionLoader .getExtensionLoader(SpiDemoService.class); // 獲取實體類 SpiDemoService one = loader.getExtension("one"); // 測試方法 one.sayHello(); }}
回到 demo :
ExtensionLoader<SpiDemoService> loader = ExtensionLoader .getExtensionLoader(SpiDemoService.class);
1 getExtensionLoader
getExtensionLoader 是 ExtensionLoader 最核心的靜態方法,用於獲取 ExtensionLoader 實例
// org.apache.dubbo.common.extension.ExtensionLoaderpublic static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { // 可行性判斷,均忽略 if (type == null) { throw new IllegalArgumentException("Extension type == null"); } if (!type.isInterface()) { throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!"); } if (!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!"); } // 先嘗試獲取,如果獲取失敗就創建一個 ExtensionLoader // EXTENSION_LOADERS 是一個靜態 ConcurrentHashMap,用來存放 loader ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }
2 ExtensionLoader 構造器
// org.apache.dubbo.common.extension.ExtensionLoaderprivate ExtensionLoader(Class<?> type) { // 存儲要創建的 loader 的類型 this.type = type; // objectFactory 是 ExtensionFactory 類型的對象,是用來依賴注入的工廠 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader .getExtensionLoader(ExtensionFactory.class) .getAdaptiveExtension()); }
1 getAdaptiveExtension
// org.apache.dubbo.common.extension.ExtensionLoaderpublic T getAdaptiveExtension() { // cachedAdaptiveInstance 是一個 Holder 對象,Holder 是對 Object 的包裝 // 在此處先嘗試獲取實例化完成的對象,如果獲取不到,就進入加載邏輯 Object instance = cachedAdaptiveInstance.get(); if (instance == null) { // 如果之前初始化的時候報錯了,那麼錯誤會被記錄下來並緩存在此處,直接拋出 // 此處的設計應該是減少鎖消耗 if (createAdaptiveInstanceError != null) { throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } synchronized (cachedAdaptiveInstance) { // 雙鎖驗證 instance = cachedAdaptiveInstance.get(); if (instance == null) { try { // 創建實例並存儲在 Holder 對象裡 instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { // 如果報錯了就會把錯誤存儲起來 createAdaptiveInstanceError = t; throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); } } } } // 返回對象實例 return (T) instance;}
2 createAdaptiveExtension
創建實例對象:
// org.apache.dubbo.common.extension.ExtensionLoaderprivate T createAdaptiveExtension() { try { // getAdaptiveExtensionClass().newInstance() 方法會使用 Class 對象的 newInstance() 方法創建一個對象 // injectExtension(...) 則會對創建出來的對象進行依賴注入 return injectExtension((T)getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e); }}
3 injectExtension
// org.apache.dubbo.common.extension.ExtensionLoaderprivate T injectExtension(T instance) { // objectFactory 是用來依賴注入的 ExtensionFactory // 如果 objectFactory 為空,就直接返回 // 需要注意的是,只有非 ExtensionFactory 的 loader 才有 objectFactory if (objectFactory == null) { return instance; } try { // 輪訓實例對象中所有的方法 for (Method method : instance.getClass().getMethods()) { // 如果方法不是 set 方法就跳過 // 此處可以理解為,dubbo 的 spi 依賴注入需要 set 方法支持 if (!isSetter(method)) { continue; } // 如果方法被標註了 DisableInject 註解就跳過 if (method.getAnnotation(DisableInject.class) != null) { continue; } // 如果方法的參數是原始類型就跳過 // 依賴注入需要使用包裝類型 Class<?> pt = method.getParameterTypes()[0]; if (ReflectUtils.isPrimitives(pt)) { continue; } try { // 反射注入 String property = getSetterProperty(method); Object object = objectFactory.getExtension(pt, property); if (object != null) { method.invoke(instance, object); } } catch (Exception e) { logger.error("Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance;}
ExtensionFactory 是用來依賴注入的工廠:
@SPIpublic interface ExtensionFactory { <T> T getExtension(Class<T> type, String name);}
該接口在 Dubbo 中有三個默認實現類:
org.apache.dubbo.config.spring.extension.SpringExtensionFactoryorg.apache.dubbo.common.extension.factory.AdaptiveExtensionFactoryorg.apache.dubbo.common.extension.factory.SpiExtensionFactory
在開發中 SpringExtensionFactory 應該會用的更廣泛一些,本示例中此處暫時不展開。
1 AdaptiveExtensionFactory
AdaptiveExtensionFactory 是默認工廠:
import org.apache.dubbo.common.extension.Adaptive;import org.apache.dubbo.common.extension.ExtensionFactory;import org.apache.dubbo.common.extension.ExtensionLoader;import java.util.ArrayList;import java.util.Collections;import java.util.List;@Adaptivepublic class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; // 構造器 public AdaptiveExtensionFactory() { ExtensionLoader<ExtensionFactory> loader = ExtensionLoader .getExtensionLoader(ExtensionFactory.class); // AdaptiveExtensionFactory 會將 SpiExtensionFactory 和 SpringExtensionFactory 放置在 factories 列表裡 List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); } // 使用 AdaptiveExtensionFactory 去獲取實體類的時候, // 會調用 spi 或者 spring 的 ext 工廠去嘗試獲取實體類 @Override public <T> T getExtension(Class<T> type, String name) { for (ExtensionFactory factory : factories) { T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; }}
2 SpiExtensionFactory
import org.apache.dubbo.common.extension.ExtensionFactory;import org.apache.dubbo.common.extension.ExtensionLoader;import org.apache.dubbo.common.extension.SPI;public class SpiExtensionFactory implements ExtensionFactory { @Override public <T> T getExtension(Class<T> type, String name) { // spi 工廠用於解析 spi 註解 if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { // 如果傳入的 type 是一個被 spi 注釋的接口,那麼會初始化一個它的 class loader ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); // 初始化對象 if (!loader.getSupportedExtensions().isEmpty()) { return loader.getAdaptiveExtension(); } } return null; }}
回到 demo :
SpiDemoService one = loader.getExtension("one");
1 getExtension
// org.apache.dubbo.common.extension.ExtensionLoaderpublic T getExtension(String name) { // 非空驗證,忽略 if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException("Extension name == null"); } // 默認機制,會去找名稱為 dubbo 的實例 // 一般用不到 if ("true".equals(name)) { return getDefaultExtension(); } // 如果之前不存在這個名稱對應的 Holder 對象,此處會創建一個空白的 Holder // 調用 get() 方法會獲得空對象 final Holder<Object> holder = getOrCreateHolder(name); Object instance = holder.get(); if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { // 創建對象實例,並裝進 holder 中 instance = createExtension(name); holder.set(instance); } } } // 返回實例 return (T) instance;}
2 createExtension
// org.apache.dubbo.common.extension.ExtensionLoaderprivate T createExtension(String name) { // 如果 class 不存在就報錯 Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { // 嘗試獲取 class 對應的實例,如果不存在就創建 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } // 進行依賴注入 injectExtension(instance); Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (CollectionUtils.isNotEmpty(wrapperClasses)) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } initExtension(instance); return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: " + t.getMessage(), t); }}
1 總結
spi 的代碼有點繞,做一下總結。
ExtensionLoader
ExtensionLoader 是整個 spi 系統的門面,也是 spi 的實例結合類。
內置對象
記錄了 class 和 loader 的對應關係
記錄了 class 和實例對象的對應關係。可以認為是一個靜態的全局 bean 容器。
主要方法
嘗試創建這個 class 對應的 loader 對象;
但是在創建一般 spi 接口的 loader 對象之前,還會先創建 ExtensionFactory 的 loader 對象。
按照需求實例化對象,放置到 EXTENSION_INSTANCES 對象中,然後做依賴注入並返回給使用者。
ExtensionFactory
用來做依賴注入的工廠。
ExtensionFactory 也是被 ExtensionLoader 管理的一類特殊的 spi 類。
2 未完成
dubbo 的 spi 還有很重要的一部分即為 @Adaptive 註解的使用,這部分涉及動態代理,較為複雜,有空開新篇講。
本文僅為個人的學習筆記,可能存在錯誤或者表述不清的地方,有緣補充
來源:https://www.tuicool.com/articles/fMBzMvU