# DubboSPI

想要理解 Dubbo,理解 Dubbo SPI 是必须的,在 Dubbo 中,提供了大量的扩展点,基于 Dubbo SPI 机制进行加载。如官网所示: SPI扩展实现

17种扩展点实现,可见 Dubbo SPI 机制在整个框架中的地位。那么, Dubbo SPI 为什么这么重要?为什么不使用 Java 自带的 SPI 机制?这些疑问,可以从官网文档中获得答案。

Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。 Dubbo 改进了 JDK 标准的 SPI 的以下问题:

  • JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。
  • 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
  1. 上面第一点,了解 JDK SPI 的加载机制就会明白,它会一次性加载所有的实现。然而,从上面的图中可知,Dubbo的扩展点有 N 多种,如果一次性加载所有的扩展点,不仅加载时间变长,也会造成内存等其他一些的资源浪费。
  2. 第二点,没用过 ScriptEngine ,暂不影响。
  3. 第三点,Dubbo 不想过度依赖其他第三方框架,所以自己实现了一套 IoC 和 AOP。

# 扩展点特性

参考:Dubbo 官方文档 扩展点特性 (opens new window)

  1. 扩展点自动包装
    • 自动包装扩展点的 Wrapper 类。ExtensionLoader 在加载扩展点时,如果加载到的扩展点有拷贝构造函数,则判定为扩展点 Wrapper 类。
    • Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。
    • 扩展点的 Wrapper 类可以有多个,也可以根据需要新增。
    • 通过 Wrapper 类可以把所有扩展点公共逻辑移至 Wrapper 中。新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。
  2. 扩展点自动装配
    • 加载扩展点时,自动注入依赖的扩展点。加载扩展点时,扩展点实现类的成员如果为其它扩展点类型,ExtensionLoader 在会自动注入依赖的扩展点。ExtensionLoader 通过扫描扩展点实现类的所有 setter 方法来判定其成员。即 ExtensionLoader 会执行扩展点的拼装操作。
  3. 扩展点自适应
    • ExtensionLoader 注入的依赖扩展点是一个 Adaptive 实例,直到扩展点方法执行时才决定调用是哪一个扩展点实现。
    • Dubbo 使用 URL 对象(包含了Key-Value)传递配置信息。
    • 扩展点方法调用会有URL参数(或是参数有URL成员)
    • 这样依赖的扩展点也可以从URL拿到配置信息,所有的扩展点自己定好配置的Key后,配置信息从URL上从最外层传入。URL在配置传递上即是一条总线。
    • 在 Dubbo 的 ExtensionLoader 的扩展点类对应的 Adaptive 实现是在加载扩展点里动态生成。指定提取的 URL 的 Key 通过 @Adaptive 注解在接口方法上提供。
  4. 扩展点自动激活
    • 对于集合类扩展点,比如:Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker 等,可以同时加载多个实现,此时,可以用自动激活来简化配置。

# 代码结构

Dubbo SPI 在 dubbo-commonextension 包实现,如下图所示:
SPI代码结构

下面开始进行源码分析:

# ExtensionLoader

ExtensionLoader 是 Dubbo 的扩展点加载器,这是 Dubbo SPI 的核心。 再回顾一下前面的一个例子:

@SPI
public interface Color {
	void draw(URL url);
}

public class Red implements Color {
	@Override
	public void draw(URL url) {
		System.out.println(" I am Red");
	}
}

public class Blue implements Color {
	@Override
	public void draw(URL url) {
		System.out.println(" I am blue");
	}
}

@Adaptive
public class Black implements Color {
	@Override
	public void draw(URL url) {
		System.out.println(" I am black");
	}
}

// src/main/resources/META-INF/dubbo/com.alibaba.dubbo.demo.model.dubbo_spi.Color
black=com.alibaba.dubbo.demo.model.dubbo_spi.Black
blue=com.alibaba.dubbo.demo.model.dubbo_spi.Blue
red=com.alibaba.dubbo.demo.model.dubbo_spi.Red

public class Dubbo_SPI_Test {
	@Test
	public void adaptiveTest() {
        URL url = URL.valueOf("test://localhost/test");
		ExtensionLoader<Color> extensionLoader = ExtensionLoader.getExtensionLoader(Color.class);
		final Color color = extensionLoader.getAdaptiveExtension();
		color.draw(url);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

找出关键的2句话:

  1. ExtensionLoader.getExtensionLoader(Color.class):获取扩展点加载器。
  2. extensionLoader.getAdaptiveExtension() :获取自适应扩展点。

下面详细分析这2句代码,这两句分析透彻了,Dubbo SPI 机制也了解差不多了。

首先看下 ExtensionLoader 类中的成员变量:

/**
 * 默认的 SPI 扩展点加载目录。
 */
private static final String SERVICES_DIRECTORY = "META-INF/services/";
/**
 * Dubbo SPI 扩展点 和 用户自定义扩展点 加载目录。
 */
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
/**
 * Dubbo SPI 内部扩展点加载目录。
 */
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");

// ============================== 静态属性 ==============================

/**
 * 扩展点加载器缓存。
 * key: 扩展接口    value:对应的 扩展点加载器。
 */
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
/**
 * 拓展实现类集合。
 * key:扩展实现类    value:扩展对象。
 * 例如:key 为 Class<AccessLogFilter>,value 为 AccessLogFilter 对象。
 */
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

// ============================== 对象属性 ==============================

/**
 * 扩展接口。
 * 例如: Protocol。
 */
private final Class<?> type;
/**
 * 对象工厂(用于实现 IoC)。
 * 用于调用 {@link #injectExtension(Object)} 方法,向拓展对象注入依赖属性。
 */
private final ExtensionFactory objectFactory;
/**
 * 缓存的 拓展名 与 拓展类 的映射。
 * 通过 {@link #loadExtensionClasses} 加载。
 */
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
/**
 * 缓存的 拓展实现类 集合。
 * 通过 {@link #loadExtensionClasses} 加载。
 *
 * 不包含如下两种类型:
 *  1. 自适应扩展实现类。例如:AdaptiveExtensionFactory
 *  2. 拓展 Wrapper 实现类。例如:ProtocolFilterWrapper。拓展 Wrapper 实现类,会添加到 {@link #cachedWrapperClasses} 中。
 */
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
/**
 * 扩展名与 @Activate 的映射。
 * 例如:AccessLogFilter。
 * 用于 {@link #getActivateExtension(URL, String)}
 */
private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
/**
 * 缓存的拓展对象集合。
 * key:拓展名  value:拓展对象。
 * 通过 {@link #loadExtensionClasses} 加载。
 * 例如:Protocol 拓展
 *   key:dubbo value:DubboProtocol
 *   key:injvm value:InjvmProtocol
 */
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
/**
 * 缓存的自适应(Adaptive)拓展对象。
 */
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
/**
 * 缓存的自适应拓展对象的类。
 * {@link #getAdaptiveExtensionClass()}
 */
private volatile Class<?> cachedAdaptiveClass = null;
/**
 * 缓存的默认拓展名。
 * 通过 {@link SPI} 注解获得。
 */
private String cachedDefaultName;
/**
 * 创建 {@link #cachedAdaptiveInstance} 时发生的异常。
 * 发生异常后,不再创建,参见 {@link #createAdaptiveExtension()}
 */
private volatile Throwable createAdaptiveInstanceError;
/**
 * 拓展 Wrapper 实现类集合。
 * 带唯一参数为拓展接口的构造方法的实现类。
 * 通过 {@link #loadExtensionClasses} 加载。
 */
private Set<Class<?>> cachedWrapperClasses;
/**
 * 拓展名 与 加载对应拓展类发生的异常 的 映射。
 * key:拓展名  value:异常
 * 在 {@link #loadFile(Map, String)} 时,记录。
 */
private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

看到上面的成员变量,头大!但是,不能怂!继续撸!

# ExtensionLoader.getExtensionLoader(Color.class)

// Step 1
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 interface!");
    }
    // 检查是否带有 SPI 注解,如果没有,直接抛出异常!
    if (!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
    }
    // 先从缓存获取 ExtensionLoader,如果缓存没有,创建一个 新的 ExtensionLoader。
    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;
}

// Step 2
// 私有化构造器,说明不想被外部调用。将实例化的权限 收紧。
private ExtensionLoader(Class<?> type) {
    this.type = type;
    // 如果 type 是 ExtensionFactory 工厂类类型,objectFactory = null
    // 否则,获取 ExtensionFactory 类的 扩展类加载器,最后获取 自适应的 扩展类。
    // objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    // TODO 上面是源码,下面是改写,主要用于分析 ExtensionLoader.getExtensionLoader(ExtensionFactory.class)
    if (type == ExtensionFactory.class) {
        objectFactory = null;
    } else {
        // 第一次进入,type = Color.class,所以进到 else 分支。
        // 此时先获取一个 ExtensionFactory 扩展点的工厂类,这里又回到了 Step 1,
        // 在 Step 1 中会执行 new ExtensionLoader<T>(ExtensionFactory.class),便有了一个 扩展点加载器的工厂类,并加入 EXTENSION_LOADERS 缓存。
        ExtensionLoader<ExtensionFactory> factoryExtensionLoader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        objectFactory = factoryExtensionLoader.getAdaptiveExtension();  // 核心
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

通过上面的分析可以看出,在获取 Color 的扩展点加载器之前,先创建了一个 ExtensionFactory 的扩展点加载器,然后通过 factoryExtensionLoader.getAdaptiveExtension() 获取其自适应扩展点,继续深入分析该方法的调用过程。 注意:此时的 typeExtensionFactory.class,并非 Color.class

// Step 3:先从缓存中获取,如果缓存没有就调用 createAdaptiveExtension 创建一个自适应扩展点,然后将其放入缓存。
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;
}

// Step 4
// 1. 调用 getAdaptiveExtensionClass 方法获取自适应拓展 Class 对象
// 2. 通过反射进行实例化
// 3. 调用 injectExtension 方法向拓展实例中注入依赖
private T createAdaptiveExtension() {
    try {
        // 获取自适应拓展类,并通过反射实例化
        // return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        // 源码是上面这一句,下面这几句为改写,就是为了看清楚每一步的过程。
        Class<?> clazz = getAdaptiveExtensionClass(); // 核心
        T t = (T) clazz.newInstance();
        return injectExtension(t);
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}

// Step 5
private Class<?> getAdaptiveExtensionClass() {
    // 通过 SPI 获取所有的拓展类
    getExtensionClasses();  // 核心
    // 检查缓存,若缓存不为空,则直接返回缓存
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    // 创建自适应拓展类
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

// Step 6
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;
}

// Step 7:正式加载 扩展点
// 此时的 type 还是 ExtensionFactory,并且 ExtensionFactory 源码上也加了 @SPI 注解,说明 ExtensionFactory 这个工厂类本身就是一个扩展点。
private Map<String, Class<?>> loadExtensionClasses() {
    // 获取 SPI 注解,这里的 type 变量是在调用 getExtensionLoader 方法时传入的
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if (defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        if ((value = value.trim()).length() > 0) {  // ExtensionFactory 的 @SPI 没有标注 value,所以不会进到下面的 if 代码块。
            // 对 SPI 注解内容进行切分(逗号切分)
            String[] names = NAME_SEPARATOR.split(value);
            // 检测 SPI 注解内容是否合法,不合法则抛出异常
            if (names.length > 1) {
                throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names));
            }
            // 设置默认名称,参考 getDefaultExtension 方法
            if (names.length == 1)
                cachedDefaultName = names[0];
        }
    }

    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    // 加载指定文件夹下的配置文件
    // 1. "META-INF/dubbo/internal/";
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    // 2. "META-INF/dubbo/";
    loadDirectory(extensionClasses, DUBBO_DIRECTORY);
    // 3. "META-INF/services/";
    loadDirectory(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

上面的 Step 3、4、5、6、7 这几步,主要就是为了加载 ExtensionFactory 的自适应扩展点,因为此时的 type 还是 ExtensionFactory
具体的加载过程就在 loadDirectory(Map<String, Class<?>> extensionClasses, String dir) 方法之中。这里会加载 3个 位置的 文件:

  • META-INF/dubbo/internal/:dubbo 内部自带的扩展点目录
  • META-INF/dubbo/:用户自定义的扩展点目录
  • META-INF/services/:JDK 的 扩展点目录

在对应的目录找到各自的扩展点加载器:

  1. META-INF/dubbo/internal/ 目录:
    dubboInternalSPI2 dubboInternalSPI
// dubbo-config-spring 包
// src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory

// dubbo-common 包
// src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
1
2
3
4
5
6
7
8

注意: 在其他版本中,把 dubbo-config-spring 包中的 ExtensionFactory 扩展和 dubbo-common 包中的 ExtensionFactory 扩展又整合在一个文件中,如下:

// src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
1
2
3
4

上面的变化不影响分析源码,只是换了一个位置,加载过程还是一样的。

  1. META-INF/dubbo/ 目录:
    userSPI
// src/main/resources/META-INF/dubbo/com.alibaba.dubbo.demo.model.dubbo_spi.Color 我自定义的
black=com.alibaba.dubbo.demo.model.dubbo_spi.Black
blue=com.alibaba.dubbo.demo.model.dubbo_spi.Blue
red=com.alibaba.dubbo.demo.model.dubbo_spi.Red
1
2
3
4
  1. META-INF/services/ 目录:
    暂不考虑

下面接上步 Step 7 继续深入分析加载过程。进入 loadDirectory(Map<String, Class<?>> extensionClasses, String dir) 方法:

// Step 8
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("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t);
    }
}

// Step 9
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(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                        exceptions.put(line, e);
                    }
                }
            }
        } finally {
            reader.close();
        }
    } catch (Throwable t) {
        logger.error("Exception when load extension class(interface: " + type + ", class file: " + resourceURL + ") in " + resourceURL, t);
    }
}

// Step 10
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.");
    }
    // 检测目标类上是否有 Adaptive 注解
    if (clazz.isAnnotationPresent(Adaptive.class)) {
        if (cachedAdaptiveClass == null) {
            // 设置 cachedAdaptiveClass 缓存
            cachedAdaptiveClass = clazz;  // AdaptiveExtensionFactory
        } else if (!cachedAdaptiveClass.equals(clazz)) {
            throw new IllegalStateException("More than 1 adaptive class found: " + cachedAdaptiveClass.getClass().getName() + ", " + clazz.getClass().getName());
        }
        // 检测 clazz 是否是 Wrapper 类型
    } else if (isWrapperClass(clazz)) {
        Set<Class<?>> wrappers = cachedWrapperClasses;
        if (wrappers == null) {
            cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
            wrappers = cachedWrapperClasses;
        }
        // 存储 clazz 到 cachedWrapperClasses 缓存中
        wrappers.add(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("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
            }
        }
        // 切分 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("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

通过上面的 Step 8、9、10 ,实际流程其实就是:loadDirectory ---> loadResource ---> loadClass。下面再来具体分析下:

  • loadDirectory:按顺序加载扩展点,先加载 Dubbo 内部自带的(META-INF/dubbo/internal/)扩展点,再加载 用户自定义的(META-INF/dubbo/internal/) 扩展点。
  • loadResource:按行读取每个文件中的扩展点,然后进行实例化(Class.forName(line, true, classLoader)),最后调用 loadClass 进行加载。
  • loadClass:正式加载各个扩展点并且加入对应的缓存。改方法也有几个核心步骤:
    • 检测目标类上是否有 Adaptive 注解,如果有,设置 cachedAdaptiveClass 缓存,这一步确定了 自适应扩展点
    • 监测目标类上是否是 Wrapper 类型,如果是,加入到 cachedWrapperClasses 缓存
    • 最后,监测目标类是否有默认 构造器,如果没有抛出异常,这里可以说明一点,所有的扩展点都必须有个默认的构造器。接下来,有个非常重要的步骤,获取激活的扩展点,最后才是把扩展点的 name 和 Class 缓存起来。如下代码:
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
    // 如果类上有 Activate 注解,则使用 names 数组的第一个元素作为键,
    // 存储 name 到 Activate 注解对象的映射关系
    cachedActivates.put(names[0], activate);
}dc
1
2
3
4
5
6

至此为止,扩展点加载完毕,先后加载了 ExtensionFactory.class 的扩展点、 Color.class 的扩展点、 并获取到对应的 激活的自适应扩展点。也就是前面提到的内置扩展点和自定义扩展点。

// src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory 内置扩展点
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
// src/main/resources/META-INF/dubbo/com.alibaba.dubbo.demo.model.dubbo_spi.Color 我自定义的
black=com.alibaba.dubbo.demo.model.dubbo_spi.Black
blue=com.alibaba.dubbo.demo.model.dubbo_spi.Blue
red=com.alibaba.dubbo.demo.model.dubbo_spi.Red
1
2
3
4
5
6
7
8

注意:此时,只是加载了各个扩展点的类型,并没有真正的实例化扩展点。真正的实例化是在 首次获取自适应扩展点 的时候。

ExtensionLoader<Color> extensionLoader = ExtensionLoader.getExtensionLoader(Color.class); // 这一步只是前奏
final Color color = extensionLoader.getAdaptiveExtension(); // 在这一步中进行的实例化,回到上面的 Step 4,
1
2

getAdaptiveExtension() ---> createAdaptiveExtension() 方法的核心片段

Class<?> clazz = getAdaptiveExtensionClass();
T t = (T) clazz.newInstance(); // 实例化
return injectExtension(t);
1
2
3

到这里,才完整的看到 自适应扩展点 的加载过程。这里只是简单的演示,真正的扩展点加载还是比较复杂的,虽然是演示,也能算得上 窥一斑而知全豹

更新时间: 2021-08-12 08:15:01