“载营魄抱一,能无离乎?
专气致柔,能如婴儿乎?
涤除玄览,能无疵乎?
爱民治国,能无以智乎?
天门开阖,能为雌乎?
明白四达,能无为乎?
生之畜之,生而不有,为而不恃,长而不宰,是谓玄德。”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 | ("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:老子《道德经》第十章,老子故里,中国鹿邑。