ExtensionLoader 注入的依赖扩展点是一个 Adaptive 实例,直到扩展点方法执行时才决定调用是哪一个扩展点实现。
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
Dubbo 改进了 JDK 标准的 SPI 的以下问题:
- JDK标准的SPI是一次性实例化所有的扩展点实现,比较消耗资源,而dubbo是在方法执行时才决定调用哪个扩展点
- JDK 如果扩展点加载失败,连扩展点的名称都拿不到了
- 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
dubbo默认约定文件放在META-INF/dubbo/internal下。
扩展点加载
ExtensionLoader#getExtensionLoader(Class type)
@SuppressWarnings("unchecked")
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 an interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
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;
}
加载扩展点,主要分为三步:
- 校验类型是否为接口
- withExtensionAnnotation校验是否包含SPI注解
- EXTENSION_LOADERS 缓存获取扩展点,如果不存在则生成对应的扩展点并放入缓存
初始化 ExtensionLoader
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
初始化 ExtensionFactory ExtensionLoader
ExtensionLoader.getExtensionLoader(ExtensionFactory.class) 一次回调获取到对应的ExtensionFactory的扩展点。
但是在回调时,我们看到以上的构造函数返回了null。
type == ExtensionFactory.class ? null
所以ExtensionFactory的扩展点是在ExtensionLoader#getDefaultExtension 初始化。
/**
* synchronized in getExtensionClasses
*/
private Map<String, Class<?>> loadExtensionClasses() {
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}
ExtensionFactory 类图
ExtensionLoader#getExtension()
public T getExtension(String name) {
return getExtension(name, true);
}
public T getExtension(String name, boolean wrap) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
if ("true".equals(name)) {
return getDefaultExtension();
}
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
instance = createExtension(name, wrap);
holder.set(instance);
}
}
}
return (T) instance;
}
- 校验数据是否正常
- 创建Holder 对象
- 创建createExtension
Holder
/**
* Helper Class for hold a value.
*/
public class Holder<T> {
private volatile T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
createExtension
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
总结
整个ExtensionFactory的加载扩展其实宏观分为以下几个步骤:
1、LoadFile加载ExtensionFactory对应的SPI文件及内容。
2、ExtensionFactory对应的AdaptiveExtensionFactory的对象实例化。
3、AdaptiveExtensionFactory构造函数内部初始化SpringExtensionFactory和SpiExtensionFactory。