美文网首页
dubbo中ExtensionLoader工作原理

dubbo中ExtensionLoader工作原理

作者: 越陌先生 | 来源:发表于2021-09-05 18:19 被阅读0次

    前言

    我们在设计程序的时候 要考虑到扩展性 以应对不断变化 ,让应用程序接口和具体实现的完全解藕。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)

    相关文章

      网友评论

          本文标题:dubbo中ExtensionLoader工作原理

          本文链接:https://www.haomeiwen.com/subject/pcijwltx.html