dubbo中ExtensionLoader工作原理

前言

我们在设计程序的时候 要考虑到扩展性 以应对不断变化 ,让应用程序接口和具体实现的完全解藕。dubbo 所有的功能组件都拥有良好的扩展性,得益于使用SPI 动态加载不同的扩展点实现类。作为SPI的核心实现 ,ExtensionLoader 能够在运行时生成扩展实现类,并能够自适应扩展,获取自动激活扩展类。下面就讲讲ExtensionLoader 的工作原理
ExtensionLoader 中获取扩展点有三种形式 分别为
1 getExtension(String name) --获取普通扩展类
2 getAdaptiveExtension() -- 获取自适应看扩展类
3 getActivateExtension(URL url, String key) --获取自动激活扩展类
下面分别讲述三种获取扩展点的实现

获取普通扩展类 --getExtension(String name)

image.png

下面看看 getExtension(String name) 每一步操作

1 根据传入参数扩展点名 判断是否缓存是否已存在该扩展点

   final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                // 判断缓存中是否存在扩展点实例
                if (instance == null) {
                    // 扩展点不存在 则调用createExtension 创建
                    instance = createExtension(name, wrap);
                    holder.set(instance);
                }
            }
        }

2 创建扩展点

在createExtension中首先是根据不同路径读取扩展点描述信息
路径有
META-INF/dubbo/external/
META-INF/dubbo/internal/
META-INF/dubbo/
META-INF/services/
其中META-INF/services/ 兼容了java spi的默认路径
createExtension 调用了 getExtensionClasses来加载不同路径下的扩展点信息 我们看下此方法及其内部调用的 loadExtensionClasses

private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    // 此处为加载扩展点class
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
private Map<String, Class<?>> loadExtensionClasses() {
        // 获取并缓存默认的实现类
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // strategies 为包含不同路径信息实例化类集合
        for (LoadingStrategy strategy : strategies) {
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }

全局静态变量strategies 由方法 loadLoadingStrategies 解析LoadingStrategy文件并数组实例化生成

// 解析加载策略化类实例 返回数组
 private static LoadingStrategy[] loadLoadingStrategies() {
        return stream(load(LoadingStrategy.class).spliterator(), false)
                .sorted()
                .toArray(LoadingStrategy[]::new);
    }

loadDirectory方法 根据LoadingStrategy生成对应的扩展点class信息

private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
                               boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
        String fileName = dir + type;
        try {
            Enumeration<java.net.URL> urls = null;
            // 返回当前 类加载器 ExtensionLoader
            ClassLoader classLoader = findClassLoader();

            // try to load from ExtensionLoader's ClassLoader first
            if (extensionLoaderClassLoaderFirst) {
                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
                if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                    urls = extensionLoaderClassLoader.getResources(fileName);
                }
            }

            if (urls == null || !urls.hasMoreElements()) {
                if (classLoader != null) {
                    urls = classLoader.getResources(fileName);
                } else {
                    urls = ClassLoader.getSystemResources(fileName);
                }
            }

            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    // 加载生成class信息
                    loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

loadResource 加载class信息

 private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
                              java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
        try {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
                String line;
                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;
                            // 配置文件内容格式 xxx=包名.类名
                            int i = line.indexOf('=');
                            if (i > 0) {
                                name = line.substring(0, i).trim();
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0 && !isExcluded(line, excludedPackages)) {
                                // 再次调用 加载类信息
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name, overridden);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }

loadClass 保存class信息

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            // 注释了自适应扩展类 缓存自适应扩展类
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            // 缓存包装类
            cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    // 缓存类名和class的对应关系
                    cacheName(clazz, n);
                    // 保存扩展类class信息
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }

loadExtensionClasses 方法中还有 cacheDefaultExtensionName 获取并缓存默认的实现类 默认实现类 使用 @SPI注释 如dubbo 默认传输协议使用 netty

@SPI("netty")
public interface Transporter {
 private void cacheDefaultExtensionName() {
        // 
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation == null) {
            return;
        }

        String value = defaultAnnotation.value();
        if ((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];
            }
        }
    }

3 实例化扩展类

实例化并依赖注入其他扩展类

injectExtension(instance);

包装类注入扩展类

   if (wrap) {

                List<Class<?>> wrapperClassesList = new ArrayList<>();
                if (cachedWrapperClasses != null) {
                    wrapperClassesList.addAll(cachedWrapperClasses);
                    wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                    Collections.reverse(wrapperClassesList);
                }

                if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                    for (Class<?> wrapperClass : wrapperClassesList) {
                        Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                        if (wrapper == null
                                || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
                            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                        }
                    }
                }
            }

扩展类初始化

 initExtension(instance);

获取自适应扩展类 --getAdaptiveExtension(String name)

getAdaptiveExtension会为扩展点接口自动生成实现类字符串, 有@Adaptive 注解的方法生成默认实现,默认实现根据url中提取的Adative参数 动态加载扩展点,再根据不同的编译器编译成class文件返回

 private Class<?> createAdaptiveExtensionClass() {
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

大致分为4步
1 生成头部信息 保护 import package等

 private String generatePackageInfo() {
        return String.format(CODE_PACKAGE, type.getPackage().getName());
    }
    private String generateImports() {
        return String.format(CODE_IMPORTS, ExtensionLoader.class.getName());
    }

2 生成默认实现类名称,如果@Adaptive 中没有设置默认值 则根据类名称生成

 private String generateClassDeclaration() {
        return String.format(CODE_CLASS_DECLARATION, type.getSimpleName(), type.getCanonicalName());
    }

3 循环生成方法

    for (Method method : methods) {
            code.append(generateMethod(method));
        }
  1. 生成调用结果代码
compiler.compile(code, classLoader);

获取自动激活扩展类 --getActivateExtension(URL url, String key, String group)

逻辑就是根据url中指定的参数 自动激活对应的扩展类
getActivateExtension根据url参数配置 获取要激活的扩展类信息 并按顺序排序 最终由 获取普通扩展类 getExtension 依次生成
代码相对简单 这里不再贴上 有兴趣的可以参考 源码
org.apache.dubbo.common.extension.ExtensionLoader#getActivateExtension(org.apache.dubbo.common.URL, java.lang.String[], java.lang.String)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容