1. 程式人生 > >4、Dubbo的SPI機制分析3-Dubbo的IOC依賴注入

4、Dubbo的SPI機制分析3-Dubbo的IOC依賴注入

這裡的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