深度解析dubbo扩展技术dubbo spi(实现一)

1. ExtensionLoader类介绍

咱们dubbo spi扩展技术主要是在ExtensionLoader 中实现的,包括寻找扩展,创建扩展,缓存扩展等扩展管理的整个生命周期,同时也对外提供类获取扩展的功能。其实一个ExtensionLoader对象就代表着一个需要扩展的接口,然后里面缓存了它的扩展点实现类。
1.1寻找扩展的方法:
在这里插入图片描述
1.2创建扩展的方法:
在这里插入图片描述
在这里插入图片描述
1.3缓存扩展(提供了一系列对象元素进行缓存):
在这里插入图片描述
1.4 外提供类获取扩展:
在这里插入图片描述
当然不局限于这些方法,这里只是大体说一下,后面详细分析。

2.ExtensionLoader类成员介绍

    // java 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*");
    // 缓存 extensionloader 们
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
    // 缓存了instance  , key是 class对象,value 是对应的实例  , 扩展实现类集合
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

这几个类成员主要是定义扩展配置文件的位置与缓存ExtensionLoader对象。

3.ExtensionLoader成员变量介绍


    private final Class<?> type;//接口类型  , 扩展接口

    private final ExtensionFactory objectFactory;// factory  一般是适配类 AdaptiveExtensionFactory

    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();

    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();  // 存储 class s

    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    private volatile Class<?> cachedAdaptiveClass = null;
    private String cachedDefaultName;   // 默认的 @SPI("dubbo")
    private volatile Throwable createAdaptiveInstanceError;

    private Set<Class<?>> cachedWrapperClasses;

    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();

这些成员变量,主要是缓存当前ExtensionLoader对象的扩展接口类型,缓存扩展点实现类,自适应类,包装类等等。

4.窥探ExtensionLoader对象创建

ExtensionLoader类的构造方法是private的,我们不能通过外部new的方式来创建对象。ExtensionLoader提供了static方法来供我们获取自己想要的ExtensionLoader对象。
咱们先从 getExtensionLoader(Class type) 方法开始,

 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!");
        }
        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) {// dubbo 中很多的处理都是这样的 创建先put  然后再get 获取值,保证线程安全
            //创建
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

在getExtensionLoader方法中,首先判断你传过来的type (也就是扩展点接口类型)不能是null,而且类型还需要是个interface,之后就是判断有没有@SPI注解,再往下走就是从EXTENSION_LOADERS这个map中获取该类型的ExtensionLoader对象,如果没有获取到的话就new ExtensionLoader(type),然后使用putIfAbsent方法put,不存在就put到map中,之后再获取一遍返回。
接着我们再看看new ExtensionLoader(type) 这个构造

private ExtensionLoader(Class<?> type) {
        this.type = type;

        //扩展工厂
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

首先是将type 赋值给成员变量type,相当于缓存起来,接着判断type是不是ExtensionFactory类型的,如果不是的话就通过ExtensionFactory 的ExtensionLoader对象获取它的自适应扩展对象,在这里也就是AdaptiveExtensionFactory 对象,然后将这个对象赋值给objectFactory成员。如果是ExtensionFactory类型的,objectFactory赋值null;
该部分就是ExtensionLoader对象创建源码了,接下来我们在看下扩展实现类的具体创建过程。

5.扩展点实现类对象创建过程

在dubbo中,getExtensionLoader(Class type) 方法往往与 getExtension(String name) 方法组合使用,也就是获取到某个扩展点ExtensionLoader对象后接着通过name获取具体的实现类。

 public T getExtension(String name) {
 		//判空
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        // 从缓存中根据name获取实现类对象
        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.set(instance);
                }
            }
        }
        return (T) instance;
    }

首先是参数校验,然后就是从实现类缓存的成员中获取该name的实现类holder,如果没有找到就创建一个。
接着就是调用holder.get()方法,获取到具体的实现类。这里我们要先看下这个holder是什么。

public class Holder<T> {
    private volatile T value;
    public void set(T value) {
        this.value = value;
    }
    public T get() {
        return value;
    }
}

可以看出holder中封装了一个修饰的volatile成员。
接着上面的话题,如果没有在Holder获取到具体的value,也就是value是null。这时走了createExtension(name) 方法。然后将createExtension(name) 方法返回值设置到holder中。

 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);// setter 注入
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;  //所有的wrapper缓存
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {// 包装Wrapper
                    instance = 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);
        }
    }

createExtension方法第一行就调用getExtensionClasses()方法,其实这个方法作用就是从配置文件中获取实现类的class们,它的返回值是Map<String, Class<?>> ,key就是咱们的name,然后value就对应的是扩展实现类的class,getExtensionClasses()这个方法稍后再说,这个就当作***问题一*** , 这里咱们就当Class<?> clazz = getExtensionClasses().get(name);这行有了返回值,接着往下走,从EXTENSION_INSTANCES 这个成员变量中获取这个class对应的具体实例,如果没有,就执行clazz.newInstance()创建一个然后塞到EXTENSION_INSTANCES 这个成员中缓存。接着往下
走injectExtension(instance);这个就是具体的setter注入,这个咱们后面说,就当作咱们的***问题二***,再往后就是这个扩展点有包装类的话,就将扩展点对象传入到包装类的构造中进行包装,这个就当作咱们***问题三***,到这里咱们想要的具体对象就创建完成了。

6.本篇总结

本篇主要说了ExtensionLoader 类在dubbo spi的地位作用,它管理了扩展点实现的生命周期,实现了自适应,IOC,自动包装等特性,之后我们又介绍了ExtensionLoader 的类成员与成员变量,这些成员主要是用作扩展点实现类的缓存,之后我们又说了ExtensionLoader 的创建过程与扩展点实现类的创建过程,其中我们还遗留了3个问题,
1.扩展点实现类具体寻找过程
2.setter注入过程
3.包装类的规则与包装原理
这个三个问题会在后面篇章讲述。

猜你喜欢

转载自blog.csdn.net/yuanshangshenghuo/article/details/106379634