Dubbo的扩展机制

为什么要了解Dubbo的扩展机制

Dubbo的设计中大量使用多态,通过Dubbo的扩展机制来决定调用方法的真正类型,所以想要了解Dubbo的源码是如何走下去的,一定要先懂得Dubbo的扩展机制。

Dubbo的扩展机制规范

  • 如果要扩展自定义的SPI,需要在resources目录下进行如下的配置,ExtensionLoader在初始化所有类型的子类时会对以上路径扫描。
    private static final StringSERVICES_DIRECTORY ="META-INF/services/";
    private static final StringDUBBO_DIRECTORY ="META-INF/dubbo/";
    private static final StringDUBBO_INTERNAL_DIRECTORY =DUBBO_DIRECTORY +"internal/";
    
  • 文件的名称需要和接口保持一致 xxx=com.alibaba.xxx.XxxProtocol
  • 需要在xml中进行配置

    源码分析

  • ExtensionLoader.getExtensionLoader(Class type)

这是初始化一个ExtensionLoader的入口,在Dubbo中通过ExtensionLoader来管理着不同的接口,如ContainerProtocol 等,ExtensionLoader相当于维护着接口类型以及具体实现子类Map的容器。

public static  ExtensionLoader getExtensionLoader(Class type) {
·····
       //先从缓存中取值,为null,则去new一个ExtensionLoader
       ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
       if (loader == null) {
           EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
           loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
       }
       return loader;
   }

EXTENSION_LOADERS是管理ExtensionLoader的一个Map,当我们的ExtensionLoader没有进行过初始化的时候会来执行new()操作。在ExtensionLoader的构造方法里,维护了接口类型type以及进行objectFactory的初始化,针对type不是ExtensionFactory的会把 `objectFactory 构造成如下的结构

  • objectFactory=AdaptiveExtensionFactory;
    • factories = SpiExtensionFactory 、SpringExtensionFactory

至此,一个ExtensionLoader已经构造好了,接下来需要执行的方法是ExtensionLoadergetAdaptiveExtension()方法,通过这个方法我们就可以获得我们具体的实现类了,在dubbo中的成员变量就是这样生成,如

private static final Protocolprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
  • getAdaptiveExtension ( )

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

    首先是一个双重检查锁来进行对象的加载,如果没有存在于缓存的话会createAdaptiveExtension();

private T createAdaptiveExtension() {                                                                                            
 try {                                                                                                                       
     return injectExtension((T) getAdaptiveExtensionClass().newInstance());                                                 
 } catch (Exception e) {                                                                                                     
     throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);       
 }                                                                                                                           
}

getAdaptiveExtensionClass()中是为了获取到具体实现类的Class,如果方法上有Adaptive注解则会生成代理类,否则直接获取到Class对象。具体的代码逻辑如下:

private Class getAdaptiveExtensionClass() {                                                      
 getExtensionClasses();                                                                          
 if (cachedAdaptiveClass != null) {                                                              
     return cachedAdaptiveClass;                                                                 
 }                                                                                               
 return cachedAdaptiveClass = createAdaptiveExtensionClass();                                    
}

首先还是通过双重检查获取的方式来看是否进行过某个type的处理,在loadExtensionClasses中会对SPI上的默认值进行处理,并且通过对类名去匹配具体实现类的文本文件.

private Map> getExtensionClasses() {
     Map> classes = cachedClasses.get();
     if (classes == null) {
         synchronized (cachedClasses) {
             classes = cachedClasses.get();
             if (classes == null) {
                 classes = loadExtensionClasses();
                 cachedClasses.set(classes);
             }
         }
     }
     return classes;
 }

接下来看一下方法:loadExtensionClasses()


    // 此方法已经getExtensionClasses方法同步过。
private Map> loadExtensionClasses() {
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if (defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        if (value != null && (value = value.trim()).length() > 0) {
            String[] names = NAME_SEPARATOR.split(value);
            if (names.length > 1) {
                throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                        + ": " + Arrays.toString(names));
            }
            if (names.length == 1) cachedDefaultName = names[0];
        }
    }
    Map> extensionClasses = new HashMap>();
    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    loadFile(extensionClasses, DUBBO_DIRECTORY);
    loadFile(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}

DUBBO_INTERNAL_DIRECTORY,DUBBO_DIRECTORY,SERVICES_DIRECTORY也就是在文章开始中说过的为什么要把文本放在如上目录,因为loadFile()只会从如上三个路径进行匹配。


private void loadFile(Map> extensionClasses, String dir) {
       // 1.判断当前class类上面有没有Adaptive注解,如果有,则直接赋值给cachedAdaptiveClass
       if (clazz.isAnnotationPresent(Adaptive.class)) {
           if (cachedAdaptiveClass == null) {
               cachedAdaptiveClass = clazz;
           } else if (!cachedAdaptiveClass.equals(clazz)) {
               throw new IllegalStateException("More than 1 adaptive class found: "
                       + cachedAdaptiveClass.getClass().getName()
                       + ", " + clazz.getClass().getName());
           }
       } else {
           //2.如果没有类注解,那么判断该class中没有参数是type的构造方法,如果有,则把calss放入cachedWrapperClasses中
           try {
               clazz.getConstructor(type);
               Set> wrappers = cachedWrapperClasses;
               if (wrappers == null) {
                   cachedWrapperClasses = new ConcurrentHashSet>();
                   wrappers = cachedWrapperClasses;
               }
               wrappers.add(clazz);
           } catch (NoSuchMethodException e) {
               //3.判断是否有默认构造方法
               clazz.getConstructor();
               if (name == null || name.length() == 0) {
                   name = findAnnotationName(clazz);
                   if (name == null || name.length() == 0) {
                       if (clazz.getSimpleName().length() > type.getSimpleName().length()
                               && clazz.getSimpleName().endsWith(type.getSimpleName())) {
                           name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
                       } else {
                           throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
                       }
                   }
               }
               String[] names = NAME_SEPARATOR.split(name);
               if (names != null && names.length > 0) {
                   //4.判断class是否有@Activate注解,如果有,则放入cachedActivates
                   Activate activate = clazz.getAnnotation(Activate.class);
                   if (activate != null) {
                       cachedActivates.put(names[0], activate);
                   }
                   for (String n : names) {
                       //5.缓存calss到cachedNames中
                       if (!cachedNames.containsKey(clazz)) {
                           cachedNames.put(clazz, n);
                       }
                       Class c = extensionClasses.get(n);
                       if (c == null) {
                           extensionClasses.put(n, clazz);
                       } else if (c != clazz) {
                           throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                       }
                   }
               }
           }
       }
   }
   }

在上面的这个方法中,判断当前class类上面有没有Adaptive注解,如果有,则直接赋值给cachedAdaptiveClass,如果没有则需要通过Compiler来生成class,生成的代理类如下:

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

为什么dubbo整个设计是根据url来进行驱动的,从上面生成的代理类可以看到,决定具体的实现类是什么都是通过url来进行传递的。

一点总结

  • 每个ExtensionLoader和每个type(Container,Protocol) 是一个绑定的关系。
  • ExtensionLoader中的 ExtensionFactory 是 AdaptiveExtensionFactory , AdaptiveExtensionFactory中维护了具体的SpiExtensionFactorySpringExtensionFactory
  • 如果类上有Adaptive注解则不会生成代理类,AdaptiveCompilerAdaptiveExtensionFactory;在方法上有Adaptive则会生成代理类

你可能感兴趣的:(Dubbo的扩展机制)