從dubbo內(nèi)核分析IOC&AOP

“載營魄抱一,能無離乎?
專氣致柔,能如嬰兒乎?
滌除玄覽,能無疵乎?
愛民治國,能無以智乎?
天門開闔,能為雌乎?
明白四達(dá),能無為乎?
生之畜之,生而不有,為而不恃,長而不宰,是謂玄德?!?sup>[1]

Spring從誕生至今,ioc和aop一直都是其靈魂所在,至今我們使用spring依然依賴這兩大特性:依賴注入(ioc)、面向切面編程(aop)。從設(shè)計(jì)模式上來講,卻極其簡單,無外乎工廠模式和代理模式。
今天我們從dubbo的內(nèi)核源碼入手,來看看ioc和aop是如何影響著dubbo的框架設(shè)計(jì)。

ioc在dubbo中的應(yīng)用

dubbo的ioc主要體現(xiàn)在dubbo擴(kuò)展點(diǎn)加載的環(huán)節(jié),T injectExtension(T instance)方法中。該方法只在三個(gè)地方被使用:

createAdaptiveExtension()
 --injectExtension((T) getAdaptiveExtensionClass().newInstance()) //為創(chuàng)建好的AdaptiveExtensionClass實(shí)例進(jìn)行屬性注入
 
createExtension(String name)
 --injectExtension(instance) //為創(chuàng)建好的Extension實(shí)例進(jìn)行屬性注入
 --injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //為創(chuàng)建好的wrapperClass實(shí)例進(jìn)行屬性注入

ExtensionLoader:

    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())) {//一個(gè)參數(shù)的public的setXXX(T param)方法.例如,setName(String name)
                        Class<?> pt = method.getParameterTypes()[0];//參數(shù)param的類型T,eg.String
                        try {
                            String property = method.getName().length() > 3
                                ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";//獲取屬性名XXX, eg.name
                            Object object = objectFactory.getExtension(pt, property);//實(shí)例化參數(shù)
                            if (object != null) {
                                //執(zhí)行instance.method(object)方法,這里就是執(zhí)行instance的setter方法,進(jìn)行setter注入
                                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;
    }

整個(gè)方法的作用就是通過instance對象實(shí)例的setter方法為instance的屬性賦值,完成setter注入,即IOC的最經(jīng)典的注入方式。

詳細(xì)步驟:

  • 獲取instance的setter方法,通過setter方法獲取屬性名稱property和屬性類型pt(即paramType的簡寫)
  • 使用objectFactory創(chuàng)建一個(gè)property名稱(類型為pt)的對象實(shí)例
  • 執(zhí)行instance的setter方法,注入property實(shí)例

其中,比較重要的就是:Object object = objectFactory.getExtension(pt, property);這個(gè)方法。其中的objectFactory=AdaptiveExtensionFactory實(shí)例,其屬性factories = [SpringExtensionFactory實(shí)例, SpiExtensionFactory實(shí)例]。

看一下源碼:

private final List<ExtensionFactory> factories;

    public <T> T getExtension(Class<T> type, String name) {
        /**
         * 先調(diào)用SpiExtensionFactory來實(shí)例化;
         * 如果不行,再使用SpringExtensionFactory來實(shí)例化
         */
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

SpiExtensionFactory:

public class SpiExtensionFactory implements ExtensionFactory {
    public <T> T getExtension(Class<T> type, String name) {
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {//type是接口且必須具有@SPI注解
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (loader.getSupportedExtensions().size() > 0) {//獲取type的所有ExtensionClasses實(shí)現(xiàn)的key
                return loader.getAdaptiveExtension();//獲取type的裝飾類,如果有@Adaptive注解的類,則返回該類的實(shí)例,否則返回一個(gè)動(dòng)態(tài)代理類的實(shí)例(例如Protocol$Adpative的實(shí)例)
            }
        }
        return null;
    }
}

從這里我們可以看出dubbo-SPI的另外一個(gè)好處:可以為SPI實(shí)現(xiàn)類注入SPI的裝飾類或動(dòng)態(tài)代理類。

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)) {//該context是否包含name的bean
                Object bean = context.getBean(name);//獲取name的bean,如果是懶加載或多例的bean,此時(shí)會實(shí)例化name的bean
                if (type.isInstance(bean)) {//如果obj的類型是type或其子類,與instanceof相同
                    return (T) bean;
                }
            }
        }
        return null;
    }
}

aop在dubbo中的應(yīng)用

dubbo在獲取擴(kuò)展點(diǎn)時(shí),會有如下調(diào)用:

final Protocol dubboProtocol = loader.getExtension("dubbo");
調(diào)用層級:

ExtensionLoader<T>.getExtension()
--createExtension(String name)
----getExtensionClasses().get(name)//獲取擴(kuò)展類
------loadExtensionClasses()
--------loadFile(Map<String, Class<?>> extensionClasses, String dir)
----injectExtension(instance);//ioc
----wrapper包裝;//aop

createExtension(String name),該方法源碼如下:

private T createExtension(String name) {
        /** 從cachedClasses緩存中獲取所有的實(shí)現(xiàn)類map,之后通過name獲取到對應(yīng)的實(shí)現(xiàn)類的Class對象 */
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            /** 從EXTENSION_INSTANCES緩存中獲取對應(yīng)的實(shí)現(xiàn)類的Class對象,如果沒有,直接創(chuàng)建,之后放入緩存 */
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && wrapperClasses.size() > 0) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type
                                            + ")  could not be instantiated: " + t.getMessage(),
                t);
        }
    }

這里,先給出META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol內(nèi)容:

registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper和com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper,這兩個(gè)類不含有@Adaptive注解且具有含有Protocol的單參構(gòu)造器,符合這樣條件的會被列入AOP增強(qiáng)類。放置在loader的私有屬性cachedWrapperClasses中。

此時(shí)的loader:

  • Class<?> type = interface com.alibaba.dubbo.rpc.Protocol
  • ExtensionFactory objectFactory = AdaptiveExtensionFactory(適配類)
    factories = [SpringExtensionFactory實(shí)例, SpiExtensionFactory實(shí)例]
  • cachedWrapperClasses = [class ProtocolListenerWrapper, class ProtocolFilterWrapper]

再來看createExtension(String name)中的紅色部分,就是今天的重點(diǎn)AOP。如上所講,我在cachedWrapperClasses中緩存了兩個(gè)AOP增強(qiáng)類:class ProtocolListenerWrapper和class ProtocolFilterWrapper。

首先是獲取ProtocolListenerWrapper的單參構(gòu)造器,然后創(chuàng)建ProtocolListenerWrapper實(shí)例,最后完成對ProtocolListenerWrapper實(shí)例進(jìn)行屬性注入,注意此時(shí)的instance=ProtocolListenerWrapper實(shí)例,而不再是之前的DubboProtocol實(shí)例了。之后使用ProtocolFilterWrapper以同樣的方式進(jìn)行包裝,只是此時(shí)ProtocolFilterWrapper包裝的是ProtocolListenerWrapper實(shí)例。


  1. 老子《道德經(jīng)》第十章,老子故里,中國鹿邑。 ?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容