Dubbo SPI机制分析【二】


title: Dubbo SPI机制分析【二】
tags: Dubbo,SPI,源码
grammar_cjkRuby: true


上回Dubbo SPI机制分析【一】分析了ExtensionLoader.getExtensionLoader.getAdaptiveExtension的过程,接下来继续分析ExtensionLoader.getExtension:

源码分析

getExtension

    public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        Holder holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    //实例化拓展点实现类
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
 
 

判断当前名字对应的拓展点实现类的实例是否存在,如果不存在,进行注册式单例构造实例createExtension

createExtension

    private T createExtension(String name) {
        //加载所有拓展点实现类,然后根据name获取对应的拓展点实现类
        Class clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                //以注册式单例 构造实例
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //对实例进行注入操作
            injectExtension(instance);
            //进行包装类封装
            Set> wrapperClasses = cachedWrapperClasses;
            //遍历当前拓展点的所有包装类,进行包装
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

这段代码一共做了这么几件事:

  • 加载拓展点实现类

  • 实例化拓展点实现类,并且进行注入

  • 遍历当前拓展点的包装类,并且将当前name对应的拓展点实例作为参数传入该包装类实例的构造函数,将该包装类实例化,如图

    1539354624379.png

  • 最后返回实例

总结

至此,getExtension分析完毕,主要需要注意的一点就是,通过此方法返回的实例最后可能会通过包装类进行包装,做一些特殊处理,形成一个链式调用,最后才会真正调用到特定实例的具体方法。
那么还有个问题,对于

ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()

这段代码,最后返回的Protocol类型,具体是怎样的呢?
-首先通过getAdaptiveExtension获取到的是Protocol$Adaptive:

package com.wl.dubbo;

/**
 * @Author: liumenglong
 * @Date: 2018/9/29 22:48
 * @Description:
 */

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.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;
        //根据URL获取到对应的拓展名,如果没有指定,则默认取“dubbo”
        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);
        //调用实际拓展点的refer方法,如DubboProtocol
        return extension.refer(arg0, arg1);
    }

    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();
        //根据URL获取到对应的拓展名,如果没有指定,则默认取“dubbo”
        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);
        //调用实际拓展点的export方法,如DubboProtocol
        return extension.export(arg0);
    }
}

查看方法export,最后的调用还是需要先获得具体的Protocol:

  //根据拓展名获取对应的拓展点实现类
        com.alibaba.dubbo.rpc.Protocol extension = 
                (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.
                        getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);

那么也就是说最后需要通过getExtension来获取特定的Protocol,而此时extNamedubbo,那么应该返回的就是DubboProtocol,然而在上面分析我们可以知道,DubboProtcol在实例化之后,需要经过包装类的封装,因此通过此方法最后返回的ProtocolProtocolListenerWrapper

1539354624379.png

你可能感兴趣的:(Dubbo SPI机制分析【二】)