dubbo基于spi的思想实现了可扩展式的插件编程,组件的加载都是通过spi来实现 ,只有搞清的spi的原理,才能对dubbo继续深入研究 如下
Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
下面从ExtendsionLoader开始分析dubbo spi的原理, 生成扩展点适配类的过程
- ExtensionLoader.getExtensionLoader 初始代ExtensionLoader组件,第一次加载会调用构造方法进行初始代,然后放入EXTENSION_LOADERS缓存中。
- 初始代ExtensionFactory的适配类,用于生成具体扩展类的适配类, 同样是通过spi去获取,对于ExtensionFactory稍后讲解。
- ExtensionLoader.getExtensionLoader().getAdaptiveExtension 获取单例的适配类, 第一次获取调用createAdaptiveExtension方法,放入到cachedAdaptiveInstance 这个dubbo自定义的holder中。
- createAdaptiveExtension调用如下injectExtension((T).getAdaptiveExtensionClass().newInstance()),
- getAdaptiveExtensionClass中首先调用getExtensionClasses, 第一次获取调用loadExtensionClasses获取扩展类的字节码,放入到cachedClasses缓存中。
- loadExtensionClasses方法中,首先读取@SPI注解的值,作为默认的扩展名放在 cachedDefaultName, 并在生成第8步适配类代码时使用,这样加载实现类时就默认加载注解中指定的值。
然后调用loadFile方法
依次读取路径的文件,读取key=value形式的值, 并且对读取到的类进行反射解析
META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol
META-INF/services/ com.alibaba.dubbo.rpc.Protocol
a. 判断实现类(如:AdaptiveCompiler)上有没有打上@Adaptive注解,如果打上了注解,将此类作为设配类缓存起到cachedAdaptiveClass中
b. 如果类实现没有打上@Adaptive, 判断实现类是否存在入参为接口的构造器(如ProtocolFilterWrapper),如果有作为包装类缓存到此ExtensionLoader的Set
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException(
"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException(
"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
.getExtension(extName);
return extension.export(arg0);
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
if (arg1 == null)
throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
.getExtension(extName);
return extension.refer(arg0, arg1);
}
}
扩展点实现类的加载过程, 以Protocol为例,
- Protocol.export ->ExtensionLoader.getExtensionLoader()getExtension(extName)
- getExtension中 判断cachedInstances是否包含有实现类缓存,没有则执行createExtension, 交放到缓存中。
- createExtension方法 首先调用getExtensionClasses方法从cachedClasses(加载适配类时)中获取扩展类的字节码,然后实例化,并放如EXTENSION_INSTANCES中缓存。
- 调用injectExtension去注入相关的属性
- 如果实现类有Wrapper包装对象,会实例化出包装对象,并返回,这样实际使用的是包装对象
createAdaptiveExtensionClassCode生成扩展类代码
1.完全没有Adaptive方法,则不需要生成Adaptive类
2. 没有@Adaptive的方法会抛出异常
3. 打上了@Adaptive注解的方法参数必须有URL类型参数或者有参数中存在getURL()方法
生成代码如下几行
getNameCode = String.format(“( url.getProtocol() == null ? \”%s\” : url.getProtocol() )”, defaultExtName);
s = String.format(“\n%s extension = (%
ExtensionFactory的加载过程
1. AdaptiveExtensionFactory上打有@Adaptive注解作为ExtensionFactory的适配类
2. ExtensionFactory构造方法中会调用ExtensionLoader.getSupportedExtensions()方法,从cachedClasses中获取所有类扩展,放入factoriey缓存中
3. getExtension方法会遍历所有的工厂,先调用SpiExtensionFactory.getExtension(),执行ExtensionLoader.getExtensionLoader(type).getAdaptiveExtension,获取扩展类的适配类。
若没有适配类, 则执行SpringExtensionFactory.getExtension(),实际上是从spring的容器中获取javaBean对你。