文章異常囉嗦且繞彎。java
JDK 版本 : Adoptopenjdk 14.0.1
IDE : idea 2020.2
Dubbo 版本 : dubbo 2.7.6spring
Dubbo Spi 是 Dubbo 框架擴展性的根本基礎,是基於 jdk spi 的封裝和擴展。apache
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.SPI; @SPI("dubbo") // spi 最主要的註解 public interface SpiDemoService { void sayHello(); }
一號實現類 :緩存
public class SpiDemoOneServiceImpl implements SpiDemoService { @Override public void sayHello() { System.out.println("hello 1"); } }
二號實現類 :app
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 :ide
ExtensionLoader<SpiDemoService> loader = ExtensionLoader .getExtensionLoader(SpiDemoService.class);
getExtensionLoader 是 ExtensionLoader 最核心的靜態方法,用於獲取 ExtensionLoader 實例學習
// org.apache.dubbo.common.extension.ExtensionLoader public 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; }
// org.apache.dubbo.common.extension.ExtensionLoader private ExtensionLoader(Class<?> type) { // 存儲要建立的 loader 的類型 this.type = type; // objectFactory 是 ExtensionFactory 類型的對象,是用來依賴注入的工廠 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader .getExtensionLoader(ExtensionFactory.class) .getAdaptiveExtension()); }
// org.apache.dubbo.common.extension.ExtensionLoader public 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; }
建立實例對象:測試
// org.apache.dubbo.common.extension.ExtensionLoader private 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); } }
// org.apache.dubbo.common.extension.ExtensionLoader private 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 是用來依賴注入的工廠:this
@SPI public interface ExtensionFactory { <T> T getExtension(Class<T> type, String name); }
該接口在 Dubbo 中有三個默認實現類:
org.apache.dubbo.config.spring.extension.SpringExtensionFactory org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory org.apache.dubbo.common.extension.factory.SpiExtensionFactory
在開發中 SpringExtensionFactory 應該會用的更普遍一些,本示例中此處暫時不展開。
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; @Adaptive public 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; } }
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");
// org.apache.dubbo.common.extension.ExtensionLoader public 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; }
// org.apache.dubbo.common.extension.ExtensionLoader private 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); } }
spi 的代碼有點繞,作一下總結。
ExtensionLoader 是整個 spi 系統的門面,也是 spi 的實例結合類。
內置對象
記錄了 class 和 loader 的對應關係
記錄了 class 和實例對象的對應關係。能夠認爲是一個靜態的全局 bean 容器。
主要方法
嘗試建立這個 class 對應的 loader 對象;
可是在建立通常 spi 接口的 loader 對象以前,還會先建立 ExtensionFactory 的 loader 對象。
按照需求實例化對象,放置到 EXTENSION_INSTANCES 對象中,而後作依賴注入並返回給使用者。
用來作依賴注入的工廠。
ExtensionFactory 也是被 ExtensionLoader 管理的一類特殊的 spi 類。
dubbo 的 spi 還有很重要的一部分即爲 @Adaptive 註解的使用,這部分涉及動態代理,較爲複雜,有空開新篇講。
本文僅爲我的的學習筆記,可能存在錯誤或者表述不清的地方,有緣補充