我是靠谱客的博主 忧郁手套,最近开发中收集的这篇文章主要介绍dubbo 源码深度学习(dubbo 之 SPI 扩展机制),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、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 扩展机制)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部