Dubbo 源码解析(1) - Dubbo SPI

1. Dubbo SPI 简介、小Demo

 Dubbo SPI 和 Demo 直接看官网 https://dubbo.apache.org/zh/docs/v2.7/dev/source/dubbo-spi/

 

2. Dubbo SPI 源码分析

直接进入 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 an interface!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }

        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#getExtensionLoader 方法很简单,先从 EXTENSION_LOADERS 缓存中获取一个 ExtensionLoader, 如果缓存中没有, new 一个 ExtensionLoader 加入缓存并返回。结束

 

 进入 ExtensionLoader#getExtension(java.lang.String) 方法

    public T getExtension(String name) {
        return getExtension(name, true);
    }

 一个空壳方法,调用同名构造方法 ExtensionLoader#getExtension(java.lang.String, boolean) 

 

 进入 ExtensionLoader#getExtension(java.lang.String, boolean)  方法

    /**
     * 真正找到给定 name 的 extension 的方法,
     * 先从 {@link ExtensionLoader#cachedInstances} 缓存中获取 extension,
     * 如果缓存中不存在, 调用 {@link ExtensionLoader#createExtension(java.lang.String, boolean)}
     * 创建一个 extension 加入到缓存中并返回
     * @param name
     * @param wrap
     * @return
     */
    public T getExtension(String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    //创建扩展实例
                    instance = createExtension(name, wrap);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

 这才是真正获取 extension 的方法,先调用 ExtensionLoader#getOrCreateHolder 方法从 cachedInstances 缓存中获取被 Holder 包装的 extension 实例

    private Holder<Object> getOrCreateHolder(String name) {
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<>());
            holder = cachedInstances.get(name);
        }
        return holder;
    }

 如果实例不存在,使用 DCL 方式加锁,调用 ExtensionLoader#createExtension 方法创建一个 extension 实例,加入holder,最后返回实例

 

 进入 ExtensionLoader#createExtension 方法和 

    /**
     * 创建 extension instance,
     * STEP1 从 {@link ExtensionLoader#cachedClasses} 缓存中取出 extension class,
     * 如果 cachedClasses 不存在, 调用 {@link ExtensionLoader#loadExtensionClasses()}加载所有 extension class 加入缓存并返回
     * STEP2 从 {@link ExtensionLoader#EXTENSION_INSTANCES} 缓存中取出 extension class 的 instance,
     * 如果 instance 为空, 通过反射创建一个 instance 加入 EXTENSION_INSTANCES 缓存中
     * STEP3 调用 {@link ExtensionLoader#injectExtension(java.lang.Object)} 注入值,这一步是 Dubbo IOC 的具体实现
     * STEP4 迭代 {@link ExtensionLoader#cachedWrapperClasses} 创建 wrapper, 这一步是 Dubbo AOP 的具体实现
     * STEP5 调用 {@link ExtensionLoader#initExtension(java.lang.Object)} 初始化 instance
     * 返回 instance
     * @param name
     * @param wrap
     * @return
     */
    @SuppressWarnings("unchecked")
    private T createExtension(String name, boolean wrap) {
        /* 先从 cachedClasses 缓存中取出 extension class,
         * 如果 cachedClasses 不存在, 调用 loadExtensionClasses() 加载 extension class 加入缓存并返回
         */
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            //从 EXTENSION_INSTANCES 缓存中取出 extension class 的 instance,
            // 如果 instance 为空, 通过反射创建一个instance 加入 EXTENSION_INSTANCES 缓存中
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }

            //为 extension 注入值,其实就是调用 extension 的 setter 方法设置值
            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);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

  ExtensionLoader#createExtension 方法会调用 ExtensionLoader#getExtensionClasses 方法,

 

 进入 ExtensionLoader#getExtensionClasses 方法和 createExtension 方法一起看

    /**
     * 先加载所有扩展类保存到缓存中再返回
     */
    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;
    }

 ExtensionLoader#createExtension 主要走以下几步:

  1. STEP1:从 cachedClasses 中缓存中获取所有 extension class,如果缓存中取到的为空,使用 DCL 方式加锁,调用 ExtensionLoader#loadExtensionClasses 方法加载所有 extension class 加入缓存并返回;
  2. STEP2: 从 extension class 列表中选择一个与 name 对应的 class,如果 class 为空,直接抛出异常,如果 class 不为空,从 EXTENSION_INSTANCES 缓存中根据 class 获取一个 instance,如果 instance 为空,通过反射创建一个 instance 并加入缓存;
  3. STEP3:调用 ExtensionLoader#injectExtension 方法注入值,这一步其实就是调用 instance 的 setter 设置值,这一步其实就是 Dubbo IOC 的具体实现
  4. STEP4:迭代 cachedWrapperClasses 属性创建 wrapper,这一步其实就是 Dubbo AOP 的具体实现
  5. STEP5:调用 ExtensionLoader#initExtension 方法初始化 instance, 最后返回

  

 进入 ExtensionLoader#loadExtensionClasses 方法

    /**
     * 加载指定 {@link ExtensionLoader#type} 类型的 Class 列表,
     * 迭代 {@link ExtensionLoader#strategies} 并通过调用{@link ExtensionLoader#loadDirectory(java.util.Map, java.lang.String, java.lang.String, boolean, boolean, java.lang.String...)}
     * 加载 extension class
     * strategies 主要有三个实现类
     * 1. {@link DubboInternalLoadingStrategy}, 负责加载 META-INF/dubbo/internal/ 目录下的 class
     * 2. {@link DubboLoadingStrategy}, 负责加载 META-INF/dubbo/ 目录下的 class
     * 2. {@link ServicesLoadingStrategy}, 负责加载 META-INF/services/ 目录下的 class
     * synchronized in getExtensionClasses
     */
    private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();

        for (LoadingStrategy strategy : strategies) {
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());

            //这一步是为了兼容老版本的dubbo设置的,dubbo 未交给 apache 管理之前包名是以 com.alibaba 开头
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }

 这一步其实就是迭代 ExtensionLoader#strategies 属性并通过调用 ExtensionLoader#loadDirectory(Map, String, String, boolean, boolean, String...) 方法来加载 extension class,strategies 主要有三个实现,分别是

  • DubboInternalLoadingStrategy, 负责加载 META-INF/dubbo/internal/ 目录下的 class 
  • DubboLoadingStrategy, 负责加载 META-INF/dubbo/ 目录下的 class 
  • ServicesLoadingStrategy, 负责加载 META-INF/services/ 目录下的 class

 

 进入ExtensionLoader#loadDirectory(Map, String, String, boolean, boolean, String...) 方法

 

    /**
     * 加载指定 dir 目录下的 class 并保存到 extensionClasses 中,
     * 下一步调用调用 {@link ExtensionLoader#loadResource(java.util.Map, java.lang.ClassLoader, java.net.URL, boolean, java.lang.String...)} 加载指定资源
     * @param extensionClasses 加载的 class 的保存集合
     * @param dir 加载的目录
     * @param type 加载的类型
     * @param extensionLoaderClassLoaderFirst 是否先从ExtensionLoader的类加载器加载, 一般情况下为 false
     * @param overridden 是否要将后加载的 class 覆盖前加载的同名的 class,一般情况下为 true
     * @param excludedPackages 要排除的加载的包
     */
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
                               boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
        String fileName = dir + type;
        try {
            //获取指定 dir 下的 type 名称命名的文件
            Enumeration<java.net.URL> urls = null;
            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();
                    //加载资源
                    loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

 这一步先分别尝试通过当前线程的类加载器和加载 ExtensionLoader 的类加载器来加载资源,如果都加载失败,下一步再通过 ExtensionLoader#loadResource 方法加载资源

  

 进入 ExtensionLoader#loadResource 方法

    /**
     * 加载指定 resourceURL 下的资源文件,
     * 下一步调用 {@link ExtensionLoader#loadClass(java.util.Map, java.net.URL, java.lang.Class, java.lang.String, boolean)} 加载资源文件中的指定类
     * @param extensionClasses 加载的 class 的保存集合
     * @param classLoader 类加载器
     * @param resourceURL 要加载的资源文件的 URL
     * @param overridden 是否要将后加载的 class 覆盖前加载的同名的 class,一般情况下为 true
     * @param excludedPackages 要排除的加载的包
     */
    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;
                            //以等号为分隔符将 line 分隔成两部分
                            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);
        }
    }

 这一步再调用 ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 方法加载资源文件中的指定类

 

 进入 ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 方法

    /**
     * 加载指定类
     * @param extensionClasses 加载的 class 的保存集合
     * @param resourceURL 资源文件URL
     * @param clazz 要加载的类
     * @param name extensionClasses 中要保存的类的key
     * @param overridden 是否要将后加载的 class 覆盖前加载的同名的 class,一般情况下为 true
     * @throws NoSuchMethodException
     */
    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)) {
            //如果 class 加上了 Adaptive 注解,class 赋值给 cachedAdaptiveClass 属性当做缓存保存起来
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            //如果是包装类,class 加入 cachedWrapperClasses 缓存
            cacheWrapperClass(clazz);
        } else {
            // 程序进入此分支,表明 clazz 是一个普通的拓展类
            clazz.getConstructor();
            // 如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name
            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);
                }
            }

            //将 name 用逗号分隔,一个 name 可以变成多个 name
            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                //如果需要缓存到 cachedActivates 中,将第一个 name 作为 cachedActivates 集合中的key
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    //保存根据 class 查 name 的 Map 集合
                    cacheName(clazz, n);

                    //加载的 class 保存到 extensionClasses 中
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }

 ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 方法才是最终加载 extension class 的方法,该方法会先判断类上有没有加 @Adaptive 注解,如果加了,保存到 cachedAdaptiveClass 缓存中,再判断是不是一个 wrapper class,如果是,加入 cachedWrapperClasses 缓存中,如果这两个判断都不是,表明当前的 class 是一个普通的 class,先判断如果指定 name 为空, name 重新赋值为 @Extension 注解中的 value 或者是直接是类名简写。将 name 以 “,” 分隔并迭代, 如果需要缓存到 cachedActivates 中,将第一个 name 作为 cachedActivates 集合中的key,保存到 class -> name 的缓存 cachedNames 中。至此 extension class 全部加载完毕

 loadExtensionClasses 总结:ExtensionLoader#loadExtensionClasses -> ExtensionLoader#loadDirectory(Map, String, String, boolean, boolean, String...) -> ExtensionLoader#loadResource ->  ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 


 进入 ExtensionLoader#injectExtension 方法

    /**
     * 为 instance 实例注入值,
     * 具体执行步骤查找所有 setter 方法,并调用 {@link ExtensionLoader#objectFactory} 获取要注入的值通过反射注入
     * objectFactory 通常是 {@link AdaptiveExtensionFactory},
     * AdaptiveExtensionFactory 保存了一个 {@link AdaptiveExtensionFactory#factories} 集合
     * factories 保存了 {@link SpiExtensionFactory} 和 {@link org.apache.dubbo.config.spring.extension.SpringExtensionFactory}
     * 两个对象获取具体需要注入的值
     * @param instance
     * @return
     */
    private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                //判断是不是 setter 方法
                if (!isSetter(method)) {
                    continue;
                }
                //检查方法上有没有 DisableInject 注解
                /**
                 * Check {@link DisableInject} to see if we need auto injection for this property
                 */
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    //获取属性名称并从 objectFactory 根据属性类型和名称获取值并通过反射赋值
                    String property = getSetterProperty(method);
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error("Failed to inject via method " + method.getName()
                            + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }

            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

 ExtensionLoader#injectExtension 方法的作用就是为 instance 实例注入值,具体执行步骤查找所有 setter 方法,并调用 ExtensionLoader#objectFactory 获取要注入的值通过反射注入,objectFactory 通常是 AdaptiveExtensionFactory,AdaptiveExtensionFactory 保存了一个 AdaptiveExtensionFactory#factories 集合,factories 保存了 SpiExtensionFactory 和 SpringExtensionFactory 两个对象获取具体需要注入的值

 

 进入 ExtensionLoader#initExtension 方法

    private void initExtension(T instance) {
        if (instance instanceof Lifecycle) {
            Lifecycle lifecycle = (Lifecycle) instance;
            lifecycle.initialize();
        }
    }

 ExtensionLoader#initExtension 方法就是判断 instance是否实现自 Lifecycle, 如果是,调用其 initialize 方法

 

 至此 Dubbo SPI 加载 extension 结束

posted @ 2021-03-02 23:31  programmLover  阅读(98)  评论(0)    收藏  举报