概述
一、dubbo 的SPI 机制
首先,dubbo的SPI 是对 JDK SPI的扩展增强。SPI扩展机制通过 ExtensionLoader<T> 来实现完成,扩展实现在调用时进行动态的加载实例化。
1. 实现的原理,通过ServiceLoader 加载 META-INF/services 下的 文件,加载文件实例化核心配置类。通过SPI 加载 META-INF/services 下的 com.apache.dubbo.common.extension.LoadingStratgegy. 加载 com.apache.dubbo.common.extension.DubboInternalLoadingStrategy / com.apache.dubbo.common.extension.DubboLoadingStrategy / com.apache.dubbo.common.extension.ServicesLoadingStrategy并且进行 new 实例化后放在ExtensionLoader 的静态变量 loadingStrategies 集合中。
2. 动态的调用生成扩展类,首先获取 ExtensionLoader<T> ,如,type 为Protocol时为例进行说明,
2.1 ExtensionLoader.getExtensionLoader(Protocol.class) 此时 type = Protocol.class ,不等于 ExtensionFactory.class, 所以会首先获取 ExtensionFactory 的扩展 ,即 ExtensionLoader.getExtensionLoader(ExtensionFactory.class)。
2.2 然后 通过 getAdaptiveExtension() 获取自适应的扩展实现。即首先回去加载读取 META-INF/services 下的 com.apache.dubbo.extension.ExtensionFactory 的文件, 解析读取得到 3个类:SpringExtensionFactory, SpiExtensionFactory, AdaptiveExtensionFactory。
2.3 通过 getAdaptiveExtension() 获取到 AdaptiveExtensionFactory 后,Protocol的 objectFactory 就可以设置 值 AdaptiveExtensionFactory。这样 Protocol的 ExtensionLoader 就完整了。type = Protocol.class ;objectFactory = AdaptiveExtensionFactory .
2.4 重点就是 protocol的 loader . getExtension("dubbo") 获取具体的扩展类,首先从缓存中获取所有的扩展类 getExtensionClasses(),遍历 loadingStrategies 集合,读取META-INF/dubbo/internal/ 和 META-INF/dubbo 文件夹下的 名称为 type 的全限定名的文件,并通过流 BufferdReader 读取 ‘=’ 分割,分三类进行解析
(1) @Adaptive 注解注释的类 Class<?> 对象放入到 cachedAdaptiveClass , 扩展类的实例对象在 injectExtension() 完成依赖注入之后放入 chachedAdapticeInstance 中 [Holder<?>]
注: dubbo 的依赖注入仅支持 set 方法的依赖注入 反射进行注入
(2) wrapper 进行增强的 【QosProtocolWrapper等 】 cachedWrapperClasses 集合 Set<Class<?>>
(3) 普通类型的扩展类 cachedNames - ConcurrentHashMap<Class<?>, name> ; extensionCLasses;
二、dubbo Adaptive 注解 可以作用在(1)类上 --- 作用在类上说明这个类不会生成代理,表示类的扩展加载逻辑需要人工编码完成。(2) 方法上 --- 表示拓展的加载逻辑需要由框架自动生成。
dubbo 中只有两个类是有 @Adaptive 注解修饰 AdaptiveExtensionFactory 和 AdaptiveCompiler
三、生成自适应扩展类代码
说明:dubbo 中规定了,在自适应的扩展的接口 至少包含一个含有 @Adaptive 注解的方法。否则抛出异常。
private Class<?> createAdaptiveExtensionClass() { String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); ClassLoader classLoader = findClassLoader(); org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
生成代码 首先检测 是否包含 @Adaptive 注解的方法,不包含直接抛出异常,否则,进行拼接 对应自适应的扩展类 如:Protocol$Adaptive 类 实现 Protocol 接口
生成好的代码如下:
package org.apache.dubbo.rpc; import org.apache.dubbo.common.extension.ExtensionLoader; public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol { public void destroy() { throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); } public int getDefaultPort() { throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); } public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null"); org.apache.dubbo.common.URL url = arg0.getUrl(); String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])"); org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0); } public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException { if (arg1 == null) throw new IllegalArgumentException("url == null"); org.apache.dubbo.common.URL url = arg1; String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])"); org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); return extension.refer(arg0, arg1); } public java.util.List getServers() { throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); } }
自适应扩展类生成之后,然后就是要进行编译,获取编译的 扩展类 Compiler ,获取其自适应的扩展类 getAdaptiveExtension() 得到 AdaptiveCompiler 进行编译 compiler(code, ClassLoader) -> Compiler 默认的编译类是 @SPI("javassist") -> Javassist.compiler() -> AbstractCompiler.compiler() - > JavassistCompiler.doCompiler() -> 反射进行Class<?> 的实例化返回
最后
以上就是忧郁手套为你收集整理的dubbo 源码深度学习(dubbo 之 SPI 扩展机制)的全部内容,希望文章能够帮你解决dubbo 源码深度学习(dubbo 之 SPI 扩展机制)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复