dubbo擴展點的IOC

spring是如何得到容器中管理的類的

拿到applicationContext,就能夠調用getBean方法來得到Spring的bean對象了java

public class SpringContextUtil implements ApplicationContextAware {  
    // Spring應用上下文環境  
    private static ApplicationContext applicationContext;  
    /** 
     * 實現ApplicationContextAware接口的回調方法,設置上下文環境 
     *  
     * @param applicationContext 
     */  
    public void setApplicationContext(ApplicationContext applicationContext) {  
        SpringContextUtil.applicationContext = applicationContext;  
    }  
    /** 
     * @return ApplicationContext 
     */  
    public static ApplicationContext getApplicationContext() {  
        return applicationContext;  
    }  
    /** 
     * 獲取對象 
     *  
     * @param name 
     * @return Object
     * @throws BeansException 
     */  
    public static Object getBean(String name) throws BeansException {  
        return applicationContext.getBean(name);  
    }  
}

dubbo擴展點的IOC

前文中,大體有提到一些有關IOC

  • 第一點 在講解ExtensionLoader源碼的構造函數的時候,咱們說過,每個ExtensionLoader實例都有一個 objectFactory 屬性,他是實現Ioc的關鍵;
  • 第二點 相比較於JDK的SPI機制,dubbo的SPI機制支持擴展經過setter的方式來注入其餘擴展點。
  • 第三點 在調用ExtensionLoader的getExtension方法時,在獲取了相應的class並建立了instance以後,經過injectExtension(intance)方法來經過setter的方式來注入其餘擴展點。
  • 第四點 loadFile函數解析SPI配置時,假如這個類帶@Adaptive註解,緩存到cachedAdaptiveClass。

如何實現IOC -> ExtensionLoader的injectExtension方法源碼

關鍵說明,spring

  1. 獲取instance的全部方法,並解析以set方法開頭的方法,例如setXxyy(Xxyy xxyy)。
  2. 拿到set方法的入參類型Xxyy、屬性名xxyy。
  3. 執行objectFactory.getExtension(pt, property)拿到Xxyy對應的實例。
  4. 經過反射執行set方法,注入Xxyy對象。
private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
經過上面的方法,就能夠將屬性注入到instance中,實現自動裝配(IOC)。下面咱們來看一下 objectFactory.getExtension(pt, property)是如何工做的。

objectFactory屬性

上篇文章中,提到在獲取Container擴展點接口對應的ExtensionLoader的時候,會執行私有ExtensionLoader構造函數。
private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
由於此時type是Container.class,即objectFactory = ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension();
當type爲ExtensionFactory.class時,即 objectFactory = null.
咱們能夠看出,全部非ExtensionFactory.class擴展點接口都會執行ExtensionFactory對應的ExtensionLoader實例的getAdaptiveExtension()方法返回一個ExtensionFactory實例,即objectFactory對象。不然,objectFactory對象爲null。

核心方法 -> ExtensionLoader的getAdaptiveExtension方法源碼

  • getAdaptiveExtension 獲取帶有Adaptive註解的擴展實現類緩存

    • createAdaptiveExtension()建立實例app

      • injectExtension() 自動注入IOC函數

        • getAdaptiveExtensionClass() ---執行cachedAdaptiveClass對象的構造函數this

          • getExtensionClasses() ---解析全部的擴展點實現code

            • loadExtensionClasses() ---加載擴展類對象

              • loadFile() --- 從固定的文件路徑,解析加載對應的擴展點實現【上一篇已經說過,這個地方會加載幾種情形的擴展實現類,包括拿到cachedAdaptiveClass對象】
          • 返回cachedAdaptiveClass --- 返回loadFile()方法中構造的cachedAdaptiveClass對象
        • 執行 cachedAdaptiveClass.newInstance() ---執行AdaptiveExtensionFactory的構造函數

ExtensionFactory的實現類AdaptiveExtensionFactory帶有Adaptive標籤,另外兩個實現類SpiExtensionFactory、SpringExtensionFactory就是正常的實現類,也是咱們見的最多的那種擴展點實現類。接口

### AdaptiveExtensionFactory源碼
關鍵說明,
1. factories屬性,全部的非@Adaptive類的ExtensionFactory實例的集合,之後全部與ExtensionFactory打交道的操做都交給AdaptiveExtensionFactory,
2. injectExtension方法中,調用的 Object object = objectFactory.getExtension(pt, property);分別調用SpiExtensionFactory、SpringExtensionFactory兩個實際的實現類。
/**
 * AdaptiveExtensionFactory
 *
 * @author william.liangf
 */
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    //全部的非@Adaptive類的ExtensionFactory實例的集合
    private final List<ExtensionFactory> factories;

    //由於ExtensionFactory對應的ExtensionLoader實例中緩存字段已經初始化好了,因此的ExtensionLoader的操做大都是從緩存中獲取的數據
    public AdaptiveExtensionFactory() {
        //從緩存的static變量EXTENSION_LOADERS中拿到ExtensionFactory對應的ExtensionLoader實例
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        //拿到loader中加載的普通的SPI擴展接口實現類的名稱,spring與spi
        // adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
        // spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
        for (String name : loader.getSupportedExtensions()) {
            //根據名稱建立對應的ExtensionFactory實例
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    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;
    }

}

SpringExtensionFactory源碼

public class SpringExtensionFactory implements ExtensionFactory {

    private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();

    public static void addApplicationContext(ApplicationContext context) {
        contexts.add(context);
    }

    public static void removeApplicationContext(ApplicationContext context) {
        contexts.remove(context);
    }

    @SuppressWarnings("unchecked")
    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;
                }
            }
        }
        return null;
    }

}

是否是有一點熟悉的味道了啊,這也算是一個首尾呼應吧~rem

這一篇到時很快就寫完了~ 下篇文章會講解擴展點是如何實現AOP的。

相關文章
相關標籤/搜索