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<?> 的实例化返回

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值