ExtensionLoader 一般使用方式
#截取 自 ServiceConfig 代码片段
public class ServiceConfig<T> extends AbstractServiceConfig {
private static final long serialVersionUID = 3033787999037024738L;
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
从上面代码我们可以发现 ExtensionLoader 自适用方式,常见的 获取一个 扩展的用法。
1. getExtensionLoader 传进去的必须是一个接口。
2. 必须 在接口上添加一个 SPI 注解,表明是一个扩展。
构造方法分析
private final ExtensionFactory objectFactory;
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
上面代码 我们发现 一个新的类 ExtensionFactory 这个是干嘛的呢?ExtensionFactory 只有一个方法,就是根据 类型 和 名称得到具体的扩展实例。
首先 如果扩展type 是 ExtensionFactory objectFactory =null,否则 = 一个自适用的 ExtensionFactory。
我们具体 看下 ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension() 的 getAdaptiveExtension 方法
// 这个对象用来存储生成的自适用的实例 比如可能是Protocol$Adaptive (这个类是动态拼接生成的 )的实例
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 重点创建 在这里
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
我们再看 createAdaptiveExtension
private T createAdaptiveExtension() {
try {
//
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
// 自适用字节码实例,比如 Protocol$Adaptive.class(动态生成) 或者 AdaptiveExtensionFactory (非动态生成)
private volatile Class<?> cachedAdaptiveClass = null;
private Class<?> getAdaptiveExtensionClass() {
// 重点方法,获取 tpye(扩展点接口)
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
//存储从扩展点配置文件读取到的 扩展点配置 key 是扩展点名称
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
// 获取 tpye(扩展点接口),从配置文件读取扩展点 放在 cachedClasses 缓存起来
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
// 从配置文件读取
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
loadExtensionClasses 读取方法不再分析,里面主要调用 loadFile方法,主要是从dir = META-INF/dubbo/internal, META-INF/dubbo/, META-INF/services/ 依次读取配置文件,文件名都是 dir+ type.getName() 如: META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol。
PS: loadFile 方法 很长,主要做了一下几点事情
1. 从配置文件读取配置放到 map<String,Class<?>> 中 key 是 扩展点名称
2. 如果扩展点 类上 标注了 @Adaptive 则把他当作 自适用扩展实现 (如果有多个扩展点 类上标记了@Adaptive 会抛出异常 ) 赋值给 cachedAdaptiveClass。 这个时候不会则把他加入 到 (ConcurrentMap<Class<?>, String> cachedNames 存储 扩展点实现 到名称的映射 ) 或者下面的 cachedWrapperClasses
3. 如果扩展点类 含有一个构造方法,传入的是 拓展点接口,则把他当作包装类放到cachedWrapperClasses( private Set<Class<?>> cachedWrapperClasses;)中
Ps: @Adaptive 作用 : 如果标记一个类,则表示该类是一个自适用的扩展点实现,如。
如果标记一个拓展点接口的方法,则dubbo 会动态生成一个拓展点实现如: Protocol$Adaptive (这个类是动态拼接生成的 )
我调试发现 Protocol$Adaptive 的代码如下:
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive 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.RpcException {
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 com.alibaba.dubbo.rpc.RpcException {
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);
}
}
ExtensionFactory 自适应 类
还是接着 ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension() 这个说看下 ExtensionFactory 的自适用是什么?
通过前面的分析其实已经提到过了,就是
# dubbo 默认提供的 ExtensionFactory 有如下三个
ExtensionFactory
SpringExtensionFactory (com.alibaba.dubbo.config.spring.extension)
AdaptiveExtensionFactory (com.alibaba.dubbo.common.extension.factory)
SpiExtensionFactory (com.alibaba.dubbo.common.extension.factory)
我们看下 AdaptiveExtensionFactory 的实现
// 这里 其实相当于一个包装类(所有的扩展点都是一个包装类,委托给具体的拓展点提供实现 )
// factories 就存储了具体的扩展点
// 调用 getExtension时候 就循环 factories 拿到就返回
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
// loader.getSupportedExtensions() 得到全部扩展点名称 (前面说过这里不包括 adaptive扩展点实现,原因自己去看下com.alibaba.dubbo.common.extension.ExtensionLoader#loadFile 是没有把 自适用扩展点加入到 extensionClasses的)
for (String name : loader.getSupportedExtensions()) {
// 这里调用的是 getExtension 而不是 getAdaptiveExtension 拿到具体的扩展点
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;
}
}
获取Protocol扩展
我们分析 ServiceConfig 片段,看下它如何初始化 Protocol 的。
public class ServiceConfig<T> extends AbstractServiceConfig {
private static final long serialVersionUID = 3033787999037024738L;
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
上面 的关键是创建 是getAdaptiveExtension 方法,调用堆栈如下:
at com.alibaba.dubbo.common.extension.ExtensionLoader.createAdaptiveExtensionClass(ExtensionLoader.java:725)
at com.alibaba.dubbo.common.extension.ExtensionLoader.getAdaptiveExtensionClass(ExtensionLoader.java:720)
at com.alibaba.dubbo.common.extension.ExtensionLoader.createAdaptiveExtension(ExtensionLoader.java:709)
at com.alibaba.dubbo.common.extension.ExtensionLoader.getAdaptiveExtension(ExtensionLoader.java:444)
- locked <0x32d> (a com.alibaba.dubbo.common.utils.Holder)
at com.alibaba.dubbo.config.ServiceConfig.<clinit>(ServiceConfig.java:74)
at com.alibaba.dubbo.demo.learn1.ServiceExport.main(ServiceExport.java:37)
因为 Protocol 没有默认的 Adaptive 实现,所以dubbo 调用 createAdaptiveExtensionClass 方法,动态生成一个类,Protocol$Adaptive。
最终生成的 protocol 就是 Protocol$Adaptive的实例。
// Protocol$Adaptive 代码如下:
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive 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.RpcException {
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 com.alibaba.dubbo.rpc.RpcException {
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);
}
}
ps: 注册url
registry://192.168.41.77:2181/com.alibaba.dubbo.registry.RegistryService?application=test&dubbo=2.0.0&pid=3428&qos.port=22222®istry=zookeeper×tamp=1523250086375
总结
目前为止 已经分析了 ExtensionLoader 的使用和 加载。ExtensionFactory 的自适用实现。以及 普通扩展点 如 Protocol$Adaptive 是怎么 生成 和使用的。