Dubbo源码学习(四ExtensionLoader 扩展点加载机制,Protocol$Adaptive,ProxyFactory$Adaptive,Cluster$Adaptive)

Posted 皓月行空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo源码学习(四ExtensionLoader 扩展点加载机制,Protocol$Adaptive,ProxyFactory$Adaptive,Cluster$Adaptive)相关的知识,希望对你有一定的参考价值。

坚持一下,把源码看完,勤奋一点,不要在懒惰了,你已经落下别人很多了

环境配置:

jdk  1.7.0.17
dubbo 2.5.x
myeclipse 2014
idea 2017

SPI注解的接口

在dubbo中,采用了类似于java的spi机制进行扩展类加载

在dubbo.jar文件夹下有个META-INF/dubbo/internal文件夹下,定义了很多了扩展点加载类,如下图

这些文件名基本是类的全路径名,所有扩展类交由ExtensionLoader来统计进行加载处理

ExtensionLoader的属性和方法

private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);

    private static final String SERVICES_DIRECTORY = "META-INF/services/";
    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
    private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\\\s*[,]+\\\\s*");

    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();

    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

    // ==============================

    private final Class<?> type;

    private final ExtensionFactory objectFactory;

    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();

    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();

    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    private volatile Class<?> cachedAdaptiveClass = null;
    private String cachedDefaultName;
    private volatile Throwable createAdaptiveInstanceError;

    private Set<Class<?>> cachedWrapperClasses;

    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();

ExtensionLoader 对于外部调用来说,主要的方法是上图标注的3个方法,

我们以ServiceConfig为例,分析如下代码

private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

ExtensionLoader.getExtensionLoader

public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) 
    if (type == null)
        throw new IllegalArgumentException("Extension type == null");
    if (!type.isInterface()) 
        throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
    
    if (!withExtensionAnnotation(type)) 
        throw new IllegalArgumentException("Extension type(" + type +
                ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
    

    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    if (loader == null) 
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    
    return loader;

 ExtensionLoader.getAdaptveExtension

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;

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);
    

private Class<?> getAdaptiveExtensionClass() 
    getExtensionClasses();
    if (cachedAdaptiveClass != null) 
        return cachedAdaptiveClass;
    
    return cachedAdaptiveClass = createAdaptiveExtensionClass();

private Class<?> createAdaptiveExtensionClass() 
    String code = createAdaptiveExtensionClassCode();
    ClassLoader classLoader = findClassLoader();
    com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
 

由此我们大体可以得到最终生成的Protocol类 是通过写死的字符串来编译生成相应的对象,也就基本上大体了解了ExtensionLoader.getAdaptiveExtension 获取的类是有字符串拼接构建的,下面提出几个比较重要的Adaptive类代码

Protocol$Adaptive

public class Protocol$Adaptive 
    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   Invoker refer(Class arg0, URL arg1) throws com.alibaba.dubbo.rpc.RpcException 

        if (arg1 == null) throw new IllegalArgumentException("url == null");

        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])");
        Protocol extension = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);

        return extension.refer(arg0, arg1);

    

    public  Exporter export(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");

        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 rom url(" + 	url.toString() + ") use keys([protocol])");

        Protocol extension =(Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);

        return extension.export(arg0);

    


ProxyFactory$Adaptive

public class ProxyFactory$Adaptive implements com.alibaba.dubbo.rpc.ProxyFactory
    public java.lang.Object getProxy(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.getParameter("proxy", "javassist");
        if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + 	url.toString() + ") use keys([proxy])");
        ProxyFactory extension = (ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
        return extension.getProxy(arg0);
    
    public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, URL arg2) throws RpcException
        if (arg2 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg2;
        String extName = url.getParameter("proxy", "javassist");
        if(extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
        ProxyFactory extension =(ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
        return extension.getInvoker(arg0, arg1, arg2);
    

Cluster$Adaptive

public class Cluster$Adaptive implements Cluster 
    public Invoker join(Directory arg0) throws RpcException 
        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument 			getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = url.getParameter("cluster", "failover");
        if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.cluster.Cluster) 			name from url(" + url.toString() + ") use keys([cluster])");
        Cluster extension =(Cluster) ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(extName);
        return extension.join(arg0);
    

 

以上是关于Dubbo源码学习(四ExtensionLoader 扩展点加载机制,Protocol$Adaptive,ProxyFactory$Adaptive,Cluster$Adaptive)的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo源码学习 详解Dubbo里的SPI

Dubbo源码学习 详解Dubbo里的SPI

Dubbo源码学习 详解Dubbo里的SPI

Dubbo 源码分析 - 集群容错之 Directory

dubbo源码学习dubbo暴露服务的过程

Dubbo学习-源码学习