0%

从dubbo内核分析IOC&AOP

“载营魄抱一,能无离乎?
专气致柔,能如婴儿乎?
涤除玄览,能无疵乎?
爱民治国,能无以智乎?
天门开阖,能为雌乎?
明白四达,能无为乎?
生之畜之,生而不有,为而不恃,长而不宰,是谓玄德。”1

Spring从诞生至今,ioc和aop一直都是其灵魂所在,至今我们使用spring依然依赖这两大特性:依赖注入(ioc)、面向切面编程(aop)。从设计模式上来讲,却极其简单,无外乎工厂模式和代理模式。
今天我们从dubbo的内核源码入手,来看看ioc和aop是如何影响着dubbo的框架设计。

###ioc在dubbo中的应用
dubbo的ioc主要体现在dubbo扩展点加载的环节,T injectExtension(T instance)方法中。该方法只在三个地方被使用:

1
createAdaptiveExtension()
2
 --injectExtension((T) getAdaptiveExtensionClass().newInstance()) //为创建好的AdaptiveExtensionClass实例进行属性注入
3
4
createExtension(String name)
5
 --injectExtension(instance) //为创建好的Extension实例进行属性注入
6
 --injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //为创建好的wrapperClass实例进行属性注入

ExtensionLoader:

1
private T injectExtension(T instance) {
2
    try {
3
        if (objectFactory != null) {
4
            for (Method method : instance.getClass().getMethods()) {
5
                if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
6
                    && Modifier.isPublic(method.getModifiers())) {//一个参数的public的setXXX(T param)方法.例如,setName(String name)
7
                    Class<?> pt = method.getParameterTypes()[0];//参数param的类型T,eg.String
8
                    try {
9
                        String property = method.getName().length() > 3
10
                            ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";//获取属性名XXX, eg.name
11
                        Object object = objectFactory.getExtension(pt, property);//实例化参数
12
                        if (object != null) {
13
                            //执行instance.method(object)方法,这里就是执行instance的setter方法,进行setter注入
14
                            method.invoke(instance, object);
15
                        }
16
                    } catch (Exception e) {
17
                        logger.error("fail to inject via method " + method.getName() + " of interface "
18
                                     + type.getName() + ": " + e.getMessage(),
19
                            e);
20
                    }
21
                }
22
            }
23
        }
24
    } catch (Exception e) {
25
        logger.error(e.getMessage(), e);
26
    }
27
    return instance;
28
}

整个方法的作用就是通过instance对象实例的setter方法为instance的属性赋值,完成setter注入,即IOC的最经典的注入方式。

详细步骤:

  • 获取instance的setter方法,通过setter方法获取属性名称property和属性类型pt(即paramType的简写)
  • 使用objectFactory创建一个property名称(类型为pt)的对象实例
  • 执行instance的setter方法,注入property实例

其中,比较重要的就是:Object object = objectFactory.getExtension(pt, property);这个方法。其中的objectFactory=AdaptiveExtensionFactory实例,其属性factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]。

看一下源码:

1
private final List<ExtensionFactory> factories;
2
3
    public <T> T getExtension(Class<T> type, String name) {
4
        /**
5
         * 先调用SpiExtensionFactory来实例化;
6
         * 如果不行,再使用SpringExtensionFactory来实例化
7
         */
8
        for (ExtensionFactory factory : factories) {
9
            T extension = factory.getExtension(type, name);
10
            if (extension != null) {
11
                return extension;
12
            }
13
        }
14
        return null;
15
    }

SpiExtensionFactory:

1
public class SpiExtensionFactory implements ExtensionFactory {
2
    public <T> T getExtension(Class<T> type, String name) {
3
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {//type是接口且必须具有@SPI注解
4
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
5
            if (loader.getSupportedExtensions().size() > 0) {//获取type的所有ExtensionClasses实现的key
6
                return loader.getAdaptiveExtension();//获取type的装饰类,如果有@Adaptive注解的类,则返回该类的实例,否则返回一个动态代理类的实例(例如Protocol$Adpative的实例)
7
            }
8
        }
9
        return null;
10
    }
11
}

从这里我们可以看出dubbo-SPI的另外一个好处:可以为SPI实现类注入SPI的装饰类或动态代理类。

SpringExtensionFactory:

1
public class SpringExtensionFactory implements ExtensionFactory {
2
    private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
3
4
    public static void addApplicationContext(ApplicationContext context) {
5
        contexts.add(context);
6
    }
7
8
    public static void removeApplicationContext(ApplicationContext context) {
9
        contexts.remove(context);
10
    }
11
12
    @SuppressWarnings("unchecked")
13
    public <T> T getExtension(Class<T> type, String name) {
14
        for (ApplicationContext context : contexts) {
15
            if (context.containsBean(name)) {//该context是否包含name的bean
16
                Object bean = context.getBean(name);//获取name的bean,如果是懒加载或多例的bean,此时会实例化name的bean
17
                if (type.isInstance(bean)) {//如果obj的类型是type或其子类,与instanceof相同
18
                    return (T) bean;
19
                }
20
            }
21
        }
22
        return null;
23
    }
24
}

###aop在dubbo中的应用
dubbo在获取扩展点时,会有如下调用:

final Protocol dubboProtocol = loader.getExtension(“dubbo”);
调用层级:

1
ExtensionLoader<T>.getExtension()
2
--createExtension(String name)
3
----getExtensionClasses().get(name)//获取扩展类
4
------loadExtensionClasses()
5
--------loadFile(Map<String, Class<?>> extensionClasses, String dir)
6
----injectExtension(instance);//ioc
7
----wrapper包装;//aop

createExtension(String name),该方法源码如下:

1
private T createExtension(String name) {
2
        /** 从cachedClasses缓存中获取所有的实现类map,之后通过name获取到对应的实现类的Class对象 */
3
        Class<?> clazz = getExtensionClasses().get(name);
4
        if (clazz == null) {
5
            throw findException(name);
6
        }
7
        try {
8
            /** 从EXTENSION_INSTANCES缓存中获取对应的实现类的Class对象,如果没有,直接创建,之后放入缓存 */
9
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
10
            if (instance == null) {
11
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
12
                instance = (T) EXTENSION_INSTANCES.get(clazz);
13
            }
14
            injectExtension(instance);
15
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
16
            if (wrapperClasses != null && wrapperClasses.size() > 0) {
17
                for (Class<?> wrapperClass : wrapperClasses) {
18
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
19
                }
20
            }
21
            return instance;
22
        } catch (Throwable t) {
23
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type
24
                                            + ")  could not be instantiated: " + t.getMessage(),
25
                t);
26
        }
27
    }

这里,先给出META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol内容:

1
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
2
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
3
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
4
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
5
mock=com.alibaba.dubbo.rpc.support.MockProtocol
6
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
7
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
8
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
9
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
10
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
11
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
12
memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
13
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper和com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper,这两个类不含有@Adaptive注解且具有含有Protocol的单参构造器,符合这样条件的会被列入AOP增强类。放置在loader的私有属性cachedWrapperClasses中。

此时的loader:

  • Class<?> type = interface com.alibaba.dubbo.rpc.Protocol
  • ExtensionFactory objectFactory = AdaptiveExtensionFactory(适配类)
    factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]
  • cachedWrapperClasses = [class ProtocolListenerWrapper, class ProtocolFilterWrapper]

再来看createExtension(String name)中的红色部分,就是今天的重点AOP。如上所讲,我在cachedWrapperClasses中缓存了两个AOP增强类:class ProtocolListenerWrapper和class ProtocolFilterWrapper。

首先是获取ProtocolListenerWrapper的单参构造器,然后创建ProtocolListenerWrapper实例,最后完成对ProtocolListenerWrapper实例进行属性注入,注意此时的instance=ProtocolListenerWrapper实例,而不再是之前的DubboProtocol实例了。之后使用ProtocolFilterWrapper以同样的方式进行包装,只是此时ProtocolFilterWrapper包装的是ProtocolListenerWrapper实例。

1:老子《道德经》第十章,老子故里,中国鹿邑。