Dubbo 源码解析系列一 ExtensionLoader

来源:互联网 发布:淘宝二手收购 编辑:程序博客网 时间:2024/05/17 04:53

Dubbo作为阿里巴巴开源的RPC框架,也是业内被各大公司使用的最多的RPC框架,有些直接使用了Dubbo,有些对Dubbo进行改造,例如当当网使用的Dubbox。从本文开始,笔者将陆续介绍对Dubbo源码进行解析,本节从Dubbo中最为重要的ExtensionLoader开始讲起。

ExtensionLoader存在于common模块下,在Dubbo源码中,经常会看到这一的代码ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getDefaultExtension();下面代码是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;}

从以上实现可以看出,EXTENSION_LOADERS是作为ExtensionLoader类型的缓存中心,而EXTENSION_LOADERS的定义是

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

是static的,可以作为类属性使用,公用一个。

在得到一个ExtensionLoader后,我们最主要的是为为了获取类的实例,我们会紧接着看到getDefaultExtension()的实现

public T getDefaultExtension() {    getExtensionClasses();    if(null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) {           return null;    }    return getExtension(cachedDefaultName);}

先看下getExtensionClasses的实现

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

这里使用了双重验证锁,验证classes = cachedClasses.get();是否为null,避免由于多线程造成重复赋值。这里会跟着到loadExtensionClasses方法中去取得具体的classes

private Map<String, Class<?>> 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<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);    loadFile(extensionClasses, DUBBO_DIRECTORY);    loadFile(extensionClasses, SERVICES_DIRECTORY);    return extensionClasses;}

这里就是具体的加载classes的地方了,这段代码最终会根据loadFile方法,讲三个文件夹下的文件都加载当作扩展类,那么具体看最重要的一段代码loadFile是如何加载类的

private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {    String fileName = dir + type.getName();    try {        Enumeration<java.net.URL> urls;        ClassLoader classLoader = findClassLoader();        if (classLoader != null) {            urls = classLoader.getResources(fileName);        } else {            urls = ClassLoader.getSystemResources(fileName);        }        if (urls != null) {            while (urls.hasMoreElements()) {                java.net.URL url = urls.nextElement();                try {                    BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));                    try {                        String line = null;                        while ((line = reader.readLine()) != null) {                            final int ci = line.indexOf('#');                            if (ci >= 0) line = line.substring(0, ci);                            line = line.trim();                            if (line.length() > 0) {                                try {                                    String name = null;                                    int i = line.indexOf('=');                                     if (i > 0) {                                        name = line.substring(0, i).trim();                                        line = line.substring(i + 1).trim();                                    }                                    if (line.length() > 0) {                                        Class<?> clazz = Class.forName(line, true, classLoader);                                        if (! type.isAssignableFrom(clazz)) {                                            throw new IllegalStateException("Error when load extension class(interface: " +                                                    type + ", class line: " + clazz.getName() + "), class "                                                     + clazz.getName() + "is not subtype of interface.");                                        }                                        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 {                                            try {                                                clazz.getConstructor(type);                                                Set<Class<?>> wrappers = cachedWrapperClasses;                                                 if (wrappers == null) {                                                    cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();                                                    wrappers = cachedWrapperClasses;                                                }                                                wrappers.add(clazz);                                            } catch (NoSuchMethodException e) {                                                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) {                                                    Activate activate = clazz.getAnnotation(Activate.class);                                                    if (activate != null) {                                                        cachedActivates.put(names[0], activate);                                                    }                                                   for (String n : names) {                                                        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());                                                        }                                                    }                                                }                                            }                                        }                                    }                                } catch (Throwable t) {                                    IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);                                    exceptions.put(line, e);                                }                            }                        } // end of while read lines                    } finally {                        reader.close();                    }                } catch (Throwable t) {                    logger.error("Exception when load extension class(interface: " +                                        type + ", class file: " + url + ") in " + url, t);                }            } // end of while urls        }    } catch (Throwable t) {        logger.error("Exception when load extension class(interface: " +                type + ", description file: " + fileName + ").", t);    }}

这段代码很长,主要就是加载制定文件下一类全名为文件名的文件,然后读取文件内容,将对应的键值对添加到classes中,最后返回。

ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getDefaultExtension()具体过程如下:

  1. getExtensionLoader,获取ExtensionLoader实例

  2. getDefaultExtension,调用默认getDefaultExtension

  3. getExtensionClasses,获取所有扩展类

  4. loadExtensionClasses,利用loadFile装置所有扩展类

  5. loadFile,读取文件,加载配置文件中的扩展类,根据键值对装置到classes

以上就是ExtensionLoader具体加载一个类的过程,还有一种自适应的方式动态创建类的过程,下回分解

0 0
原创粉丝点击