Skip to content

dubbo SPI

litter-fish edited this page Jan 10, 2020 · 3 revisions

从ClassLoader引出spi

ClassLoader的简单介绍

Class的装载大体上可以分为:加载类、连接类和初始化三个阶段,在这三个阶段中,所有的Class都是由ClassLoader进行加载的,然后Java虚拟机负责连接、初始化等操作。也就是说,无法通过ClassLoader去改变类的连接和初始化行为。

Java虚拟机自带了三类ClassLoader,可以通过继承ClassLoader实现自定义的加载器

  1. BootStrap ClassLoader(启动类加载器)
  2. Extension ClassLoader(扩展类加载器)
  3. APP ClassLoader(应用类加载器,也称为系统类加载器)
  4. 自定义ClassLoader

ClassLoader双亲委托模式

在ClassLoader的结构中,字段parent,表示当前的ClassLoader的双亲是谁。在类加载的时候, 系统会判断当前类是否已经被加载,如果被加载,就会直接返回可用的类;否则就会尝试加载, 在尝试加载时,会先请求双亲处理,如果双亲请求失败,则会自己加载。

如图,应用类加载器的双亲为扩展类加载器,扩展类加载器的双亲为启动类加载器。 16c6562b34eaa153e6be9250de7167c3.png

双亲委托模式的弊端

顶层的类加载器,无法访问底层的类加载器所加载的类。

85d3dd21957b613a2b4fc73e709a8ec4.png

双亲委托模式的补充

把核心类(rt.jar)中提供外部服务,可由应用层自行实现的接口,这种方式称为spi。 上层加载器类访问由下层加载器加载的类,即实现spi接口的原理。通过Thread中的俩方法,

public ClassLoader getContextClassLoader(); // 获取线程中的上下文加载器
public void setContextClassLoader(ClassLoader cl); // 设置线程中的上下文加载器

把一个ClassLoader置于一个线程的实例之中,使该ClassLoader成为一个相对共享的实例。

2278d4a49414e414c6c165e6ba4f6eb0.png

dubbo SPI介绍

getExtensionLoader 方法用于从缓存中获取与拓展类对应的 ExtensionLoader,若缓存未命中,则创建一个新的实例。

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    if (type == null)
        throw new IllegalArgumentException("Extension type == null");
    // 确保type类型是一个接口
    if (!type.isInterface()) {
        throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
    }
    // 确保接口中存在SPI注解
    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) {
        // 创建ExtensionLoader实例
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}

先对入参进行验证确保参数类型是一个接口类型,及接口中存在SPI注解,通过验证后尝试从缓存中获取,如果缓存中不存在则创建一个新的的ExtensionLoader实例,并存入缓存中。

创建ExtensionLoader实例

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private ExtensionLoader(Class<?> type) {
    this.type = type;
    // 第一次创建时type == ExtensionFactory.class判断不成立,因此会再次调用ExtensionLoader
    // 接着在此通过getAdaptiveExtension方法获取定义的自适应扩展类
    // 如果 type == ExtensionFactory.class不成立 则 objectFactory = AdaptiveExtensionFactory
    objectFactory = (type == ExtensionFactory.class ? null :
        ExtensionLoader.getExtensionLoader(
            ExtensionFactory.class).getAdaptiveExtension());
}

ExtensionLoader.getExtensionLoader:获取扩展类加载的实例,如 getAdaptiveExtension:获取适配器扩展对象工厂AdaptiveExtensionFactory

适配器扩展对象工厂AdaptiveExtensionFactory

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
    // ExtensionFactory,dubbo提供两个实现
    // SpiExtensionFactory、SpringExtensionFactory
    private final List<ExtensionFactory> factories;
}

获取定义的自适应扩展类

public T getAdaptiveExtension() {
    // 双重锁检查机制获取缓存数据
    Object instance = cachedAdaptiveInstance.get();
    if (instance == null) {
        if (createAdaptiveInstanceError == null) {
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 缓存中不存在则尝试创建
                        instance = 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;
}

首先通过双重检查锁尝试从缓存cachedAdaptiveInstance中获取自适应扩展类实例,如果缓存中不存在则会创建一个自适应扩展类实例。

创建自适应扩展类实例

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private T createAdaptiveExtension() {
    try {
        // 先获取自适应扩展类的Class对象,然后通过反射方式创建对象,然后注入实例属性
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}

获取自适应扩展类的Class对象

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private Class<?> getAdaptiveExtensionClass() {
    // 获取扩展类
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

首先会在指定路径下获取扩展类,如果接口中被注解Adaptive修饰,表示他是一个自适应扩展类的Class对象,如果没有被注解Adaptive修饰,则会尝试创建一个自适应扩展类实例。

获取扩展类

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
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;
}

同样先通过双重锁检查机制尝试从缓存中获取扩展类对象,如果缓存中不存在则会进行加载扩展类逻辑

加载扩展类

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private Map<String, Class<?>> loadExtensionClasses() {
    // 获取SPI注解
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    // 通过SPI注解获取默认的名称
    if (defaultAnnotation != null) {
        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];
        }
    }

    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    // 接着在路径下加载扩展类:META-INF/dubbo/internal/
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    // META-INF/dubbo/
    loadDirectory(extensionClasses, DUBBO_DIRECTORY);
    // META-INF/services/
    loadDirectory(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}

首先通过SPI注解获取默认的扩展类名称,对名称进行验证,只能配置一个,然后将默认名存在cachedDefaultName属性中,以便后面使用。 接着尝试在META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/services/目录下面寻找扩展类,并将处理结果缓存到extensionClasses 集合map中。

指定路径下获取扩展类

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private void loadDirectory(
        Map<String, Class<?>> extensionClasses, String dir) {
    // fileName = 文件夹路径 + type 全限定名
    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 resourceURL = urls.nextElement();
                // 加载资源
                loadResource(extensionClasses, classLoader, resourceURL);
            }
        }
    } catch (Throwable t) {
        logger.error("...");
    }
}

首先通过 classLoader 获取所有资源链接,然后再通过 loadResource 方法加载资源。

加载资源

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private void loadResource(Map<String, Class<?>> extensionClasses,
                ClassLoader classLoader, java.net.URL resourceURL) {
    try {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(resourceURL.openStream(), "utf-8"));
        try {
            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;
                        int i = line.indexOf('=');
                        if (i > 0) {
                            // 以等于号 = 为界,截取键与值
                            name = line.substring(0, i).trim();
                            line = line.substring(i + 1).trim();
                        }
                        if (line.length() > 0) {
                            // 加载类,并通过 loadClass 方法对类进行缓存
                            loadClass(extensionClasses, resourceURL,
                                      Class.forName(line, true, classLoader), name);
                        }
                    } catch (Throwable t) {
                        IllegalStateException e = new IllegalStateException("Failed to load extension class...");
                    }
                }
            }
        } finally {
            reader.close();
        }
    } catch (Throwable t) {
        logger.error("Exception when load extension class...");
    }
}

loadResource 方法用于读取和解析配置文件,并通过反射加载类,最后调用 loadClass 方法进行其他操作

加载类

private void loadClass(
    Map<String, Class<?>> extensionClasses, java.net.URL resourceURL,
    Class<?> clazz, String name) throws NoSuchMethodException {

    if (!type.isAssignableFrom(clazz)) {
        throw new IllegalStateException("...");
    }

    // 检测目标类上是否有 Adaptive 注解
    if (clazz.isAnnotationPresent(Adaptive.class)) {
        if (cachedAdaptiveClass == null) {
            // 设置 cachedAdaptiveClass 缓存
            cachedAdaptiveClass = clazz;
        } else if (!cachedAdaptiveClass.equals(clazz)) {
            throw new IllegalStateException("...");
        }
    // 检测 clazz 是否是 Wrapper 类型
    } else if (isWrapperClass(clazz)) {
        Set<Class<?>> wrappers = cachedWrapperClasses;
        if (wrappers == null) {
            cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
            wrappers = cachedWrapperClasses;
        }
        // 存储 clazz 到 cachedWrapperClasses 缓存中
        wrappers.add(clazz);
    // 程序进入此分支,表明 clazz 是一个普通的拓展类
    } else {
        // 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常
        clazz.getConstructor();
        if (name == null || name.length() == 0) {
            // 如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name
            name = findAnnotationName(clazz);
            if (name.length() == 0) {
                throw new IllegalStateException("...");
            }
        }
        // 切分 name
        String[] names = NAME_SEPARATOR.split(name);
        if (names != null && names.length > 0) {
            Activate activate = clazz.getAnnotation(Activate.class);
            if (activate != null) {
                // 如果类上有 Activate 注解,则使用 names 数组的第一个元素作为键,
                // 存储 name 到 Activate 注解对象的映射关系
                cachedActivates.put(names[0], activate);
            }
            for (String n : names) {
                if (!cachedNames.containsKey(clazz)) {
                    // 存储 Class 到名称的映射关系
                    cachedNames.put(clazz, n);
                }
                Class<?> c = extensionClasses.get(n);
                if (c == null) {
                    // 存储名称到 Class 的映射关系
                    extensionClasses.put(n, clazz);
                } else if (c != clazz) {
                    throw new IllegalStateException("...");
                }
            }
        }
    }
}

首先根据目标类分别做不同处理:

  1. 如果目标类存在 Adaptive 注解,则设置 cachedAdaptiveClass 缓存
  2. 如果目标类是 Wrapper 类型,则存储 clazz 到 cachedWrapperClasses 缓存中
// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private boolean isWrapperClass(Class<?> clazz) {
    try {
        // 判断目标类是否存在以扩展类为参数的构造方法
        clazz.getConstructor(type);
        return true;
    } catch (NoSuchMethodException e) {
        return false;
    }
}
  1. 如果目标类是一个普通的拓展类,这边会先判断目标类是否存在Activate注解,存在则加入cachedActivates缓存中,然后以配置文件中“=”的前半部分为key,目标类为value缓存到extensionClasses map集合中。

通过上面的文件内容遍历,如果cachedAdaptiveClass实例存在,则会通过反射方式创建一个实例。

Dubbo IOC 依赖注入

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            // 遍历目标类的所有方法
            for (Method method : instance.getClass().getMethods()) {
                // 检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public
                if (method.getName().startsWith("set")
                    && method.getParameterTypes().length == 1
                    && Modifier.isPublic(method.getModifiers())) {
                    // 获取 setter 方法参数类型
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        // 获取属性名,比如 setName 方法对应属性名 name
                        String property =
                            method.getName().length() > 3
                            ? method
                                .getName()
                                .substring(3, 4).toLowerCase()
                                +
                                method.getName().substring(4)
                            : "";
                        // begin
                            // 从 ObjectFactory 中获取依赖对象
                            // objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。
                            // Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory
                        // end
                        Object object = objectFactory
                                            .getExtension(pt, property);
                        if (object != null) {
                            // 通过反射调用 setter 方法设置依赖
                            method.invoke(instance, object);
                        }
                    } catch (Exception e) {
                        logger.error("fail to inject via method...");
                    }
                }
            }
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
}

如果 objectFactory 不为空,即type == ExtensionFactory.class不成立, 则会先遍历目标类的所有方法, 接着找出以 set 开头,且方法仅有一个参数,且方法访问级别为 public的方法, 然后通过 ObjectFactory 获取依赖对象, 最后通过反射调用 setter 方法将依赖设置到目标对象中。

ObjectFactory 中获取依赖对象

// com/alibaba/dubbo/common/extension/factory/AdaptiveExtensionFactory.java
public <T> T getExtension(Class<T> type, String name) {
    // SpiExtensionFactory 和 SpringExtensionFactory
    for (ExtensionFactory factory : factories) {
        T extension = factory.getExtension(type, name);
        if (extension != null) {
            return extension;
        }
    }
    return null;
}

通过 ExtensionLoader 的 getExtension 方法获取拓展类对象

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
public T getExtension(String name) {
    if (name == null || name.length() == 0)
        throw new IllegalArgumentException("Extension name == null");
    if ("true".equals(name)) {
        // 获取默认的拓展实现类
        return getDefaultExtension();
    }
    // Holder,顾名思义,用于持有目标对象
    Holder<Object> holder = 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();
            if (instance == null) {
                // 创建拓展实例
                instance = createExtension(name);
                // 设置实例到 holder 中
                holder.set(instance);
            }
        }
    }
    return (T) instance;
}

首先输入name做一些验证,判断是否获取默认的拓展实现类,如果不是则先尝试从缓存 cachedInstances 中获取指定名称的拓展实例,如果不存在则尝试创建拓展实例,并加入 cachedInstances 缓存中。

创建拓展对象

// com/alibaba/dubbo/common/extension/ExtensionLoader.java
private T createExtension(String name) {
    // 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
    Class<?> clazz = 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);
        }
        // 向实例中注入依赖
        injectExtension(instance);
        Set<Class<?>> wrapperClasses = cachedWrapperClasses;//?????
        if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
            // 循环创建 Wrapper 实例
            for (Class<?> wrapperClass : wrapperClasses) {
                // 将当前 instance 作为参数传给 Wrapper 的构造方法,并通过反射创建 Wrapper 实例。
                // 然后向 Wrapper 实例中注入依赖,最后将 Wrapper 实例再次赋值给 instance 变量
                instance = injectExtension(
                    (T) wrapperClass.getConstructor(type).newInstance(instance));
            }
        }
        return instance;
    } catch (Throwable t) {
        throw new IllegalStateException("...");
    }
}

首先通过 getExtensionClasses 获取所有的拓展类 然后通过反射创建拓展对象 接着向拓展对象中注入依赖 --- Dubbo IOC 的具体实现 最后将拓展对象包裹在相应的 Wrapper 对象中 --- Dubbo AOP 的具体实现

如 Protocol 接口,存在 ProtocolListenerWrapper、ProtocolFilterWrapper包装器,则经过上面的AOP则会创建一个ProtocolFilterWrapper(ProtocolListenerWrapper(DubboProtocol))的实例。

Clone this wiki locally