基于:Dubbo SPI
使用Wrapper 类对扩展点进行自动包装。Wrapper 类也实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是包装真正的扩展点实现。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。
一、加载流程
ExtensionLoader<Protocol> extensionLoader = ExtensionLoader.getExtensionLoader(Protocol.class);
//获取到的实例为Wrapper类型
Protocol protocol = extensionLoader.getExtension("http");
System.out.println(protocol);
- 入参:扩展点接口Class(例如:Protocol.class)类型,初始化扩展点加载器。
- 首先利用JDK SPI机制加载所有dubbo扩展点加载策略(即开启dubbo spi功能)。ExtensionLoader#loadLoadingStrategies();
- 在构造函数中,利用加载器type记录,扩展点接口Class类型,
- 在构造函数中,初始化扩展点工厂实例(objectFactory)仍然是先。
- 如果是ExtensionFactory.class,则不需要工厂实例
- 如果非ExtensionFactory.class,则先通过步骤1,获取ExtensionFactory.class加载器,并调用getAdaptiveExtension(),获得工厂实例(objectFactory)
- 加载ExtensionFactory类型实现类,并实例化。路径:META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory
- 根据名称(例如:http),从缓存cachedClasses中获取具体实现类
- 获取SPI注解,在接口(例如:Protocol.class)配置的默认实现类名称
- 加载扩展点接口Class(例如:Protocol.class)类型所有实现类。并缓存至cachedClasses
- 反射实例化、依赖注入
- 生成包装类型,并调用初始化方法
SPI 加载器初始化
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//1.非空判断
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
}
//2.Class类必须为接口
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
}
//3.接口类必须被 @SPI 标记
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
//4.根据Class,从本地缓存中获取加载器。如果为空初始化加载器,并放入缓存中
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;
}
加载SPI 扩展点
SPI 加载流程