dubbo分析-ExtensionLoader自适应实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/taotoxht/article/details/79858747

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&registry=zookeeper&timestamp=1523250086375

总结

目前为止 已经分析了 ExtensionLoader 的使用和 加载。ExtensionFactory 的自适用实现。以及 普通扩展点 如 Protocol$Adaptive 是怎么 生成 和使用的。

猜你喜欢

转载自blog.csdn.net/taotoxht/article/details/79858747
今日推荐