4、Dubbo的SPI機制分析3-Dubbo的IOC依賴注入
阿新 • • 發佈:2019-10-07
這裡的getExtensionLoader()
詳細分析可以參見: Dubbo的SPI機制1-SPI簡單分析
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { // 刪去一些不必要的程式碼,詳細分析可以看前面幾篇分析 // 從快取中獲取與拓展類對應的ExtensionLoader 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; } private ExtensionLoader(Class<?> type) { this.type = type; // 這裡的type是AdaptiveExt.class,所以會執行後面的程式碼,載入並建立SpiExtensionFactory和SpringExtensionFactory objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { // 建立自適應拓展代理類物件並放入快取,這裡建立的就是ExtensionFactory的自適應拓展物件 instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { // 拋異常 } } } } } return (T) instance; }
private T createAdaptiveExtension() {
try {
// 分為3步:1是建立自適應拓展代理類Class物件,2是通過反射建立物件,3是給建立的物件按需依賴注入
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
// 拋異常
}
}
getExtensionClasses()
方法詳細分析可以參見: Dubbo的SPI機制1-SPI簡單分析
private Class<?> getAdaptiveExtensionClass() { // 這裡前面文章已經分析過了,它會去載入預設目錄下的ExtensionFactory的實現類,總共有3個,目錄是 // META-INF/dubbo/internal/,該目錄對應兩個檔案,檔案內容見下,由於AdaptiveExtensionFactory上面 // 標註了@Adaptive註解,所以它優先順序最高,它就是ExtensionFactory的預設實現類 getExtensionClasses(); // 如果有標註了@Adaptive註解實現類,那麼cachedAdaptiveClass不為空,直接返回 if (cachedAdaptiveClass != null) { // 這裡直接返回,cachedAdaptiveClass = AdaptiveExtensionFactory.class return cachedAdaptiveClass; } // 不會再走這一步 return cachedAdaptiveClass = createAdaptiveExtensionClass(); }
檔案1內容:
// 其中AdaptiveExtensionFactory上面標註了@Adaptive註解
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
檔案2內容:
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// 分析完了getAdaptiveExtensionClass(),它是返回AdaptiveExtensionFactory,接下來newInstance會呼叫它預設的構造方法
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// 裡面維護SpringExtensionFactory和SpiExtensionFactory
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader =
ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) {
// 分別給SpringExtensionFactory和SpiExtensionFactory建立物件並放入list中
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
}
3、Dubbo的IOC原始碼分析
// 上面已經分析過了第一行程式碼,這裡面會建立ExtensionFactory型別的變數objectFactory,這裡面維護了一個list,
// list裡面有SpringExtensionFactory和SpiExtensionFactory型別的例項,Dubbo的IOC獲取bean就是通過這兩個變數去獲取的
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
public T getExtension(String name) {
// 刪去一些程式碼
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 建立拓展例項
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
private T createExtension(String name) {
// 從配置檔案中載入所有的拓展類,可得到“配置項名稱”到“配置類”的對映關係表
// 這裡我們指定了名字dubbo,並不是通過getAdaptiveExtension方法去獲得自適應拓展類,這點要區分
// 所以這裡拿到的是com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// 也是嘗試先從快取獲取,獲取不到通過反射建立一個並放到快取中
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
// 這裡直接通過反射建立DubboAdaptiveExt的例項,然後給他依賴注入
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 依賴注入
injectExtension(instance);
return instance;
}
}
private T injectExtension(T instance) {
// 這裡為了排版好看,刪去一些異常捕捉丟擲程式碼
// objectFactory就是我們前面分析的,它裡面維護了SpringExtensionFactory和SpiExtensionFactory型別的例項
if (objectFactory != null) {
// 遍歷DubboAdaptiveExt例項的所有方法,尋找set開頭且引數為1個,且方法許可權為public的方法
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
// 獲取引數型別,這裡是AdaptiveExt.class
Class<?> pt = method.getParameterTypes()[0];
// 獲取屬性名,這裡是adaptiveExt
String property = method.getName().length() > 3 ?
method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
// 獲取容器中AdaptiveExt.class型別的名字為adaptiveExt的例項
Object object = objectFactory.getExtension(pt, property);
// 獲取之後通過反射賦值
if (object != null) {
method.invoke(instance, object);
}
}
}
}
return instance;
}
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
@Override
public <T> T getExtension(Class<T> type, String name) {
// 遍歷factory中所有的ExtensionFactory,先從SpiExtensionFactory中獲取,獲取不到在去Spring容器中獲取
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
這裡獲取自適應拓展可以參考: Dubbo的SPI機制分析2-Adaptive詳解
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
// 先看SpiExtensionFactory怎麼獲取,它是通過getAdaptiveExtension()去自適應獲取,根本
// 沒有用到name,所以這裡返回ThriftAdaptiveExt的例項
return loader.getAdaptiveExtension();
}
}
return null;
}
}
public class SpringExtensionFactory implements ExtensionFactory {
// 可以看到Spring是先根據名字去取,取不到再根據型別去取
@Override
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
for (ApplicationContext context : contexts) {
try {
return context.getBean(type);
}
}
return null;
}
}
// 所以這段程式碼輸出:thrift
@Test
public void test1(){
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
URL url = URL.valueOf("test://localhost/test");
adaptiveExtension.echo("d", url);
}
4、測試通過URL依賴注入
/**
* 測試通過URL依賴注入,將ThriftAdaptiveExt類上面的註解註釋掉,同時給AdaptiveExt方法加上註解@Adaptive("t")
*/
@Test
public void test5(){
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
Map<String, String> map = new HashMap<>();
// t這個key就是根據@Adaptive("t")定的,兩者要一致
map.put("t", "cloud");
URL url = new URL("", "", 1, map);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
adaptiveExtension.echo(" ", url);
}
上述程式碼輸出spring cloud,建立完DubboAdaptiveExt的例項給其注入依賴時,呼叫`injectExtension(instance)`,因為沒有了@Adaptive標註
的類,所以需要Dubbo自己生成自適應拓展代理類Class,生成過程可以參考: [Dubbo的SPI機制分析2-Adaptive詳解]
(https://segmentfault.com/a/1190000020384210).生成的代理類中有這樣一句關鍵
程式碼: `String extName = url.getParameter("t", "dubbo")`,因為url中有這個t引數,所以最後會呼叫cloud所對應
的SpringCloudAdaptiveExt的echo`方法,輸出spring cloud.
上述程式碼輸出spring cloud,建立完DubboAdaptiveExt的例項給其注入依賴時,呼叫
injectExtension(instance)
,因為沒有了@Adaptive標註的類,所以需要Dubbo自己生成自適應拓展代理類Class,生成過程可以參考: Dubbo的SPI機制分析2-Adaptive詳解.生成的代理類中有這樣一句關鍵程式碼:String extName = url.getParameter("t", "dubbo")
,因為url中有這個t引數,所以最後會呼叫cloud所對應的SpringCloudAdaptiveExt的echo`方法,輸出spring