本文主要是介绍dubbo分析-ExtensionLoader自适应实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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 是怎么 生成 和使用的。
这篇关于dubbo分析-ExtensionLoader自适应实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!