Dubbo源码-04-SPI

一 Dubbo SPI核心

核心实现都在ExtensionLoader中,比较重要的3个入口方法分别是

  • ExtensionLoader#getExtensionLoader() 扩展实现的加载器
  • ExtensionLoader#getDefaultExtension() 默认扩展实现
  • ExtensionLoader#getExtension(...) 根据指定的扩展名称获取对应的扩展实现
  • ExtensionLoader#getAdaptiveExtension() 获取自适应扩展

如下几个名词概念是我的个人理解

  1. 扩展点 - 一个接口,也就是SPI的接口,通过@SPI注解标识,

  2. 扩展实现 - SPI的接口具体实现,配置在classpath路径的文件中,提供给扩展加载器进行扫描

  3. 自适应扩展实现 - 区别于jdk SPI的关键,目的是为了在运行时根据特定场景获取需要的扩展实现,这个机制的实现体现在@Adaptive这个注解,该注解可以作用于类和方法

    • @Adaptive作用于类 运行时自适应扩展类
    • @Adaptive作用于方法 运行时自适应扩展方法
  4. 通过ExtensionLoader获取某个接口的自适应扩展实现

    • 如果在配置的可扫描到的实现类上有标注@Adaptive注解就直接反射使用
    • 如果没有提供@Adaptive实现类,通过编码技术生成实现

二 ExtensionLoader源码

1 getExtensionLoader()

// ExtensionLoader.java    
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>(); // 缓存 扩展接口以及对应的扩展类加载器


/**
     * 给定接口type的扩展类加载器ExtensionLoader
     */
    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        // 必要的参数校验
        if (type == null) throw new IllegalArgumentException("Extension type == null");
        // 接口的扩展加载起ExtensionLoader实例都放在缓存中
        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;
    }

2 构造方法

// ExtensionLoader.java

private final Class<?> type; // 扩展点(接口类型)

    /**
     * 除了ExtensionFactory的ExtensionLoader这个属性为空 其他的扩展接口的扩展类加载器这个属性都是AdaptiveExtensionFactory的实例
     * ExtensionFactory本身也是一个扩展接口
     * classpath文件
     *     - adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
     *     - spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
     * AdaptiveExtensionFactory实现上打上了注解@Adaptive 因此作为ExtensionFactory这个接口的默认实现
     *
     * objectFactory作用是为了解决可能存在的setter注入一个扩展
     */
    private final ExtensionFactory objectFactory;

private ExtensionLoader(Class<?> type) {
        this.type = type; // 扩展的接口
        this.objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

3 扩展接口实现类扫描

// ExtensionLoader.java
/**
     * 指定路径
     *     - META-INF/dubbo/internal/
     *     - META-INF/dubbo/
     *     - META-INF/services/
     * 对上面3个路径进行扫描 找到需要扩展的接口的配置文件
     * 轮询配置文件里面的所有键值对(key=名称 value=扩展点的扩展实现)
     * 解析过程中
     *     - 如果扩展实现上注有Adaptive注解 就把这个实现缓存在cachedAdaptiveClass
     *         - 这个实现就是type这个扩展点的自适应扩展实现适配类 getAdaptiveExtension()方法用到
     *     - 扩展实现是包装类 全部缓存到cachedWrapperClasses
     *     - 其他扩展实现都缓存到ExtensionLoader的cachedClasses
     *         - getDefaultExtension()用到
     *         - getExtension(...)用到
     */
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = this.loadExtensionClasses(); // 从指定文件加载出type这个接口的实现
                    this.cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
// ExtensionLoader.java
/**
     * 3个classpath上为type接口加载具体实现
     *     - 内置路径+接口全限定名
     *         - META-INF/dubbo/internal/xxx
     *         - META-INF/dubbo/xxx
     *         - META-INF/services/xxx
     *     - 文件内容格式是
     *         - 实现1名称=实现1全限定名
     *         - 实现2名称=实现2全限定名
     * 扫描接口type的注解SPI
     *     - 指定了name缓存起来作为默认实现名称
     *         - getDefaultExtension()使用
     * 扫描到接口type的所有指定实现 按照不同场景缓存起来
     *     - 第一个@Adaptive注解标识的实现类缓存到cachedAdaptiveClass
     *         - 给getAdaptiveExtension()创建自适应扩展适配用
     *     - 实现类是包装类的缓存到cachedWrapperClasses
     *     - 其余实现类缓存到hash表中
     *         - getDefaultExtension()使用
     *         - getExtension(...)根据名称查找实现类
     *
     */
    private Map<String, Class<?>> loadExtensionClasses() {
        /**
         * 接口type存在多实现 每个实现通过名字作区别
         * 将来外界通过getExtension(...)来获取type接口的实现
         *     - 在多实现中缓存中找需要的名称
         *     - 使用指派的默认实现
         */
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value(); // 指派为type接口默认实现的名称
            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) this.cachedDefaultName = names[0]; // type接口默认实现的名称
            }
        }

        // 缓存着type接口的多实现
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        /**
         * 3个classpath上为type接口加载具体实现
         *     - 内置路径+接口全限定名
         *         - META-INF/dubbo/internal/xxx
         *         - META-INF/dubbo/xxx
         *         - META-INF/services/xxx
         *     - 文件内容格式是
         *         - 实现1名称=实现1全限定名
         *         - 实现2名称=实现2全限定名
         */
        this.loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); // META-INF/dubbo/internal/
        this.loadDirectory(extensionClasses, DUBBO_DIRECTORY); // META-INF/dubbo/
        this.loadDirectory(extensionClasses, SERVICES_DIRECTORY); // META-INF/services/
        return extensionClasses;
    }
// ExtensionLoader.java
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) { // 扫描结果缓存到map中
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> urls;
            ClassLoader classLoader = this.findClassLoader();
            if (classLoader != null)
                urls = classLoader.getResources(fileName);
            else
                urls = ClassLoader.getSystemResources(fileName);
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    this.loadResource(extensionClasses, classLoader, resourceURL); // extensionClasses用于缓存第三优先级的实现类对象
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t);
        }
    }
// ExtensionLoader.java
/**
     * 轮询SPI文件 遍历到的所有扩展实现中 按照3个优先级缓存
     *     - 优先级1 第一个标注@Adaptive注解的实现类缓存到cachedAdaptiveClass
     *     - 优先级2 包装类型缓存到cachedWrapperClasses
     *     - 其余放到hash表中
     */
    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        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)) { // 扩展实现上注有@Adaptive注解
            if (this.cachedAdaptiveClass == null) // 将标注了@Adaptive注解的实现缓存起来 作为第一优先级
                this.cachedAdaptiveClass = clazz;
            else if (!cachedAdaptiveClass.equals(clazz)) // 扩展实现中只能存在一个标注了@Adaptive注解的实现
                throw new IllegalStateException("More than 1 adaptive class found: " + cachedAdaptiveClass.getClass().getName() + ", " + clazz.getClass().getName());
        } else if (this.isWrapperClass(clazz)) { // 扩展实现是包装类
            Set<Class<?>> wrappers = this.cachedWrapperClasses;
            if (wrappers == null) {
                this.cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = this.cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else { // 其他的扩展实现
            clazz.getConstructor();
            if (name == null || name.length() == 0) {
                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 (names != null && names.length > 0) {
                Activate activate = clazz.getAnnotation(Activate.class);
                if (activate != null)
                    this.cachedActivates.put(names[0], activate);
                for (String n : names) {
                    if (!this.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());
                }
            }
        }
    }

4 获取扩展接口的实现

基于上面已经将接口的实现类扫描出来并分别缓存起来

下述几种获取接口扩展实现逻辑大致差不多

  • 找到具体的实现类对象
  • 通过反射创建类实例对象
  • 防止实例对象通过setter方法注入属性对象也是需要扩展的,使用objectFactory指向的AdaptiveExtensionFactory对象处理

4.1 扩展实现类对象

4.1.1 自适应扩展实现getAdaptiveExtension()

// ExtensionLoader.java
/**
     * 当前扩展接口的自适应扩展实现
     *     - 取缓存
     *     - 创建扩展点的自适应扩展实现
     *         - 实现类反射创建实例对象
     *             - 扫文件路径过程中缓存着@Adaptive标识的实现类
     *             - 没有指定@Adaptive标识 编码实现
     *         - 对实例对象setter方法检查
     *     - 存缓存
     */
    @SuppressWarnings("unchecked")
    public T getAdaptiveExtension() {
        Object instance = this.cachedAdaptiveInstance.get();
        // 典型的synchronized DCL
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get(); // 双检查
                    if (instance == null) {
                        try {
                            instance = this.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);
            }
        }

        return (T) instance;
    }
// ExtensionLoader.java
/**
     * 依赖ExtensionLoader这个扩展实现加载器 为扩展点type这个接口创建合适的实现
     *     - 先找到自适应扩展实现类对象
     *         - 扫描Dubbo SPI路径过程着缓存下找到的@Adaptive标识的实现类对象
     *         - 编码技术生成类
     *     - 根据找到的类对象反射创建实例
     *     - 用AdaptiveExtensionFactory检查实例的setter方法 注入循环扩展对象
     */
    @SuppressWarnings("unchecked")
    private T createAdaptiveExtension() {
        try {
            /**
             *     - getAdaptiveExtensionClass()加载出自适应实现
             *         - 优先级1 Dubbo SPI指定扫描路径上有@Adaptive标识的实现
             *         - 优先级2 编码技术生成
             *     - newInstance() 对选择出来的唯一的type接口实现 通过反射创建实现的实例
             *     - injectExtension()
             *         - 解决扩展实现的setter属性注入依赖的问题
             */
            return this.injectExtension((T) this.getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
// ExtensionLoader.java
/**
     * 自适应扩展实现类的优先级
     *     - 缓存着的cachedAdaptiveClass 也就是扫描Dubbo SPI路径上实现类第一个@Adaptive注解标识的类对象
     *     - 编码技术实现
     */
    private Class<?> getAdaptiveExtensionClass() {
        this.getExtensionClasses(); // 加载所有扩展接口指定的实现方式
        if (this.cachedAdaptiveClass != null) // 扫描加载落站实现的时候会将@Adaptive注解标识的实现缓存起来作为扩展适配的第一优先级
            return this.cachedAdaptiveClass;
        return this.cachedAdaptiveClass = this.createAdaptiveExtensionClass(); // 没有@Adaptive注解指定默认的扩展实现 使用编码技术生成
    }
4.1.2.1 扫描出来@Adaptive注解标识的实现类对象
4.1.2.2 编码技术生成类对象
// ExtensionLoader.java
/**
     * code生成的方式对扩展点中被{@link Adaptive}修饰的方法进行编码 字节码技术生成类
     */
    private Class<?> createAdaptiveExtensionClass() {
        String code = this.createAdaptiveExtensionClassCode(); // 硬编码扩展接口的实现类(方法标注@Adaptive()注解的)
        ClassLoader classLoader = findClassLoader(); // 当前类加载器
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

4.1.2 默认实现getDefaultExtension()

// ExtensionLoader.java
public T getDefaultExtension() { // 在hash表缓存的实现类对象找@SPI指定的名称
        /**
         * 扫描Dubbo SPI指定的3个classpath路径
         *     - 将接口type指定的实现缓存起来
         *         - 实现上有注解Adaptive的单独缓存到cachedAdaptiveClass
         *         - 实现类是包装类对象 缓存到cachedWrapperClasses
         *         - 其他实现类对象缓存到hash表
         *     - 将接口type注解SPI指定的默认实现名称缓存起来
         */
        this.getExtensionClasses();
        if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName))
            return null;
        return this.getExtension(cachedDefaultName);
    }

4.1.3 指定名称的实现getExtension(...)

// ExtensionLoader.java
/**
     * 接口type的实现类缓存优先级
     *     - 实现类上第一个打上@Adaptive注解的缓存在cachedAdaptiveClass
     *     - 实现类是包装类的缓存在cachedWrapperClasses
     *     - 其他实现类缓存在hash表中
     *         - getExtension(...)就是从这份缓存中找指定名称的实现类
     *         - getDefaultExtension(...)是根据接口上@SPI的名称作为依据在这个缓存中找的实现类
     */
    @SuppressWarnings("unchecked")
    public T getExtension(String name) {
        if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) return this.getDefaultExtension(); // type接口注解@SPI标识的名称 对应的实现作为接口默认实现
        Holder<Object> holder = this.cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get(); // 接口type扩展的实现
                if (instance == null) {
                    instance = this.createExtension(name); // 缓存里面没有就去扫描里面找
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
// ExtensionLoader.java
/**
     * 指定路径
     *     - META-INF/dubbo/internal/
     *     - META-INF/dubbo/
     *     - META-INF/services/
     * 对上面3个路径进行扫描 找到需要扩展的接口的配置文件
     * 轮询配置文件里面的所有键值对(key=名称 value=扩展点的扩展实现)
     * 解析过程中
     *     - 优先级1 扩展实现上首个注有Adaptive注解 缓存在cachedAdaptiveClass
     *         - 这个实现类就是type这个扩展点的自适应扩展实现适配类 getAdaptiveExtension()方法用到
     *     - 优先级2 扩展实现是包装类 全部缓存到cachedWrapperClasses
     *     - 优先级3 其他扩展实现都缓存到ExtensionLoader的cachedClasses
     *         - getDefaultExtension()用到
     *         - getExtension(...)用到
     *         
     * 到优先级3的cachedClasses找指定名字的实现类
     */
    @SuppressWarnings("unchecked")
    private T createExtension(String name) {
        Class<?> clazz = this.getExtensionClasses().get(name); // 扫描实现类对象
        if (clazz == null) throw findException(name);
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); // 反射创建实现类的实例
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            this.injectExtension(instance); // 通过AdaptiveExtensionFactory检查实现的实例有没有setter注入扩展的场景
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses)
                    instance = this.injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

4.2 反射创建类实例对象

4.3 setter注入扩展

// ExtensionLoader.java
 /**
     * instance是type接口众多实现中最终选取的唯一作为Dubbo中的实现
     * 解决扩展实现的循环依赖场景问题
     *     - 某个扩展点的扩展实现已经获取 其中存在一个setter方法 设置的属性本身又是一个扩展实现
     */
    private T injectExtension(T instance) {
        try {
            /**
             *  ExtensionFactory的ExtensionLoader的objectFactory为空 其他都不是空
             *      - ExtensionLoader<ExtensionFactory> objectFactory是空 直接返回的实例就是AdaptiveExtensionFactory的实现实例
             *      - ExtensionLoader<T> objectFactory指向了ExtensionLoader<ExtensionFactory>对象
             */
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    // setter方法
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        /**
                         * 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]; // setxxx这个setter方法的形参 肯定只有一个参数
                        try {
                            // setxxx这个setter方法注入的属性名称xxx
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            /**
                             * Duboo是否存在SPI实现
                             *     - name是property
                             *     - 接口类型是pt
                             * 获取setter参数的扩展实现 目的是为了解决扩展实现里面的setter属性注入的依赖
                             */
                            Object object = this.objectFactory.getExtension(pt, property);
                            if (object != null)
                                method.invoke(instance, object);
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
posted @   Bannirui  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示