3. Dubbo SPI 源码分析

上一章简单演示了 Dubbo SPI 的使用方法。我们首先通过 ExtensionLoader 的 getExtensionLoader 方法获取一个 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象。这其中,getExtensionLoader 方法用于从缓存中获取与拓展类对应的 ExtensionLoader,若缓存未命中,则创建一个新的实例。该方法的逻辑比较简单,本章就不进行分析了。下面我们从 ExtensionLoader 的 getExtension 方法作为入口,对拓展类对象的获取过程进行详细的分析。

  1. public T getExtension(String name) {
  2. if (name == null || name.length() == 0)
  3. throw new IllegalArgumentException("Extension name == null");
  4. if ("true".equals(name)) {
  5. // 获取默认的拓展实现类
  6. return getDefaultExtension();
  7. }
  8. // Holder,顾名思义,用于持有目标对象
  9. Holder<Object> holder = cachedInstances.get(name);
  10. if (holder == null) {
  11. cachedInstances.putIfAbsent(name, new Holder<Object>());
  12. holder = cachedInstances.get(name);
  13. }
  14. Object instance = holder.get();
  15. // 双重检查
  16. if (instance == null) {
  17. synchronized (holder) {
  18. instance = holder.get();
  19. if (instance == null) {
  20. // 创建拓展实例
  21. instance = createExtension(name);
  22. // 设置实例到 holder 中
  23. holder.set(instance);
  24. }
  25. }
  26. }
  27. return (T) instance;
  28. }

上面代码的逻辑比较简单,首先检查缓存,缓存未命中则创建拓展对象。下面我们来看一下创建拓展对象的过程是怎样的。

  1. private T createExtension(String name) {
  2. // 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
  3. Class<?> clazz = getExtensionClasses().get(name);
  4. if (clazz == null) {
  5. throw findException(name);
  6. }
  7. try {
  8. T instance = (T) EXTENSION_INSTANCES.get(clazz);
  9. if (instance == null) {
  10. // 通过反射创建实例
  11. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
  12. instance = (T) EXTENSION_INSTANCES.get(clazz);
  13. }
  14. // 向实例中注入依赖
  15. injectExtension(instance);
  16. Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  17. if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
  18. // 循环创建 Wrapper 实例
  19. for (Class<?> wrapperClass : wrapperClasses) {
  20. // 将当前 instance 作为参数传给 Wrapper 的构造方法,并通过反射创建 Wrapper 实例。
  21. // 然后向 Wrapper 实例中注入依赖,最后将 Wrapper 实例再次赋值给 instance 变量
  22. instance = injectExtension(
  23. (T) wrapperClass.getConstructor(type).newInstance(instance));
  24. }
  25. }
  26. return instance;
  27. } catch (Throwable t) {
  28. throw new IllegalStateException("...");
  29. }
  30. }

createExtension 方法的逻辑稍复杂一下,包含了如下的步骤:

  1. 通过 getExtensionClasses 获取所有的拓展类
  2. 通过反射创建拓展对象
  3. 向拓展对象中注入依赖
  4. 将拓展对象包裹在相应的 Wrapper 对象中

以上步骤中,第一个步骤是加载拓展类的关键,第三和第四个步骤是 Dubbo IOC 与 AOP 的具体实现。在接下来的章节中,将会重点分析 getExtensionClasses 方法的逻辑,以及简单介绍 Dubbo IOC 的具体实现。