SPI机制,即Service Provider Interface,服务提供接口。此机制的作用是更加方便、灵活的获取到接口实现方,而不是硬编码到代码中。比如在dubbo中通过Protocol的refer接口获取到最终执行的invoker,但是Protocol有多种实现,有DubboProtocol,也有RegistryProtocol,那么我该使用哪一种呢?这时候Dubbo的SPI机制要解决的问题。
一 、Dubbo中的扩展点与Adaptive:
1、扩展点:
可以认为是需要被扩展的接口,比如Protocol、RegistryFactory等等。
2、Adaptive:
能动态的获取到上述扩展点的实现类,此方法能根据特定的条件来获取到实现类,方法是通过调用方法时传入的URL来找到最终实现类的key,再从配置文件中根据key找到最终的实现类。
具体如何找到我们会在接下来的源码解析中讲到其原理。
二、解析:
下面以ReferenceConfig根据protocol获取到invoker举例。
ReferenceConfig中protocol的Adaptive是这样来获取到的:
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
可以看到是通过ExtensionLoader来获取到最终的Adaptive。我们一步一步来看。
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<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;
}
下面看一下终点,获取到Adaptive实现类 ,可以看到Adaptive实现类也是单例。
public T getAdaptiveExtension() {
// 得到缓存的Adaptive实现类
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;
}
创建Adaptive的方法为直接生成扩展点 Adaptive实现的代码: