dubbo spi原理解析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012325403/article/details/54631929

dubbo基于spi的思想实现了可扩展式的插件编程,组件的加载都是通过spi来实现 ,只有搞清的spi的原理,才能对dubbo继续深入研究 如下

Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

下面从ExtendsionLoader开始分析dubbo spi的原理, 生成扩展点适配类的过程

  1. ExtensionLoader.getExtensionLoader 初始代ExtensionLoader组件,第一次加载会调用构造方法进行初始代,然后放入EXTENSION_LOADERS缓存中。
  2. 初始代ExtensionFactory的适配类,用于生成具体扩展类的适配类, 同样是通过spi去获取,对于ExtensionFactory稍后讲解。
  3. ExtensionLoader.getExtensionLoader().getAdaptiveExtension 获取单例的适配类, 第一次获取调用createAdaptiveExtension方法,放入到cachedAdaptiveInstance 这个dubbo自定义的holder中。
  4. createAdaptiveExtension调用如下injectExtension((T).getAdaptiveExtensionClass().newInstance()),
  5. getAdaptiveExtensionClass中首先调用getExtensionClasses, 第一次获取调用loadExtensionClasses获取扩展类的字节码,放入到cachedClasses缓存中。
  6. loadExtensionClasses方法中,首先读取@SPI注解的值,作为默认的扩展名放在 cachedDefaultName, 并在生成第8步适配类代码时使用,这样加载实现类时就默认加载注解中指定的值。
  7. 然后调用loadFile方法
    依次读取路径的文件,读取key=value形式的值, 并且对读取到的类进行反射解析
    META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
    META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol
    META-INF/services/ com.alibaba.dubbo.rpc.Protocol
    a. 判断实现类(如:AdaptiveCompiler)上有没有打上@Adaptive注解,如果打上了注解,将此类作为设配类缓存起到cachedAdaptiveClass中
    b. 如果类实现没有打上@Adaptive, 判断实现类是否存在入参为接口的构造器(如ProtocolFilterWrapper),如果有作为包装类缓存到此ExtensionLoader的Set

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class Protocol$Adpative 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.Invoker {
        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 java.lang.Class {
        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);
    }
}

扩展点实现类的加载过程, 以Protocol为例,

  1. Protocol.export ->ExtensionLoader.getExtensionLoader()getExtension(extName)
  2. getExtension中 判断cachedInstances是否包含有实现类缓存,没有则执行createExtension, 交放到缓存中。
  3. createExtension方法 首先调用getExtensionClasses方法从cachedClasses(加载适配类时)中获取扩展类的字节码,然后实例化,并放如EXTENSION_INSTANCES中缓存。
  4. 调用injectExtension去注入相关的属性
  5. 如果实现类有Wrapper包装对象,会实例化出包装对象,并返回,这样实际使用的是包装对象

createAdaptiveExtensionClassCode生成扩展类代码
1.完全没有Adaptive方法,则不需要生成Adaptive类
2. 没有@Adaptive的方法会抛出异常
3. 打上了@Adaptive注解的方法参数必须有URL类型参数或者有参数中存在getURL()方法
生成代码如下几行
getNameCode = String.format(“( url.getProtocol() == null ? \”%s\” : url.getProtocol() )”, defaultExtName);
s = String.format(“\n%s extension = (%

ExtensionFactory的加载过程

1. AdaptiveExtensionFactory上打有@Adaptive注解作为ExtensionFactory的适配类

2. ExtensionFactory构造方法中会调用ExtensionLoader.getSupportedExtensions()方法,从cachedClasses中获取所有类扩展,放入factoriey缓存中
3. getExtension方法会遍历所有的工厂,先调用SpiExtensionFactory.getExtension(),执行ExtensionLoader.getExtensionLoader(type).getAdaptiveExtension,获取扩展类的适配类。
若没有适配类, 则执行SpringExtensionFactory.getExtension(),实际上是从spring的容器中获取javaBean对你。

展开阅读全文

没有更多推荐了,返回首页