“天长地久。
天地所以能长且久者,以其不自生,故能长生。
是以圣人后其身而身先,外其身而身存。
非以其无私耶?
故能成其私。”[1]
jdk-SPI (Service Provider Interface)
SPI (Service Provider Interface),一种服务发现机制,为某个接口寻找服务实现的机制。dubbo-SPI就是基于此并有所加强。
在dubbo的源码中,像如下代码段会随处可见:
ExtensionLoader.getExtensionLoader(WrappedExt.class).getExtension("XXX");
这便是duboo-SPI的使用方式。
dubbo-SPI
特性:
- 自动包装
- 自动装配
- 自适应
- 自动激活
代码结构如下:
com.alibaba.dubbo.common.extension
|
|--factory
| |--AdaptiveExtensionFactory
| |--SpiExtensionFactory
| |--SpringExtensionFactory
|
|--support
| |--ActivateComparator
|
|--Activate #自动激活加载扩展的注解
|--Adaptive #自适应扩展点的注解
|--ExtensionFactory #扩展点对象生成工厂接口
|--ExtensionLoader #扩展点加载器,扩展点的查找,校验,加载等核心逻辑的实现类
|--SPI #扩展点注解
需要我们最为关心的就是ExtensionLoader,几乎所有特性都在这个类中实现。
ExtensionLoader没有提供public的构造方法,但是提供了一个public static的getExtensionLoader,这个方法就是获取ExtensionLoader实例的工厂方法。其public成员方法中有三个比较重要的方法:
- getActivateExtension :根据条件获取当前扩展可自动激活的实现
- getExtension : 根据名称获取当前扩展的指定实现
- getAdaptiveExtension : 获取当前扩展的自适应实现
ExtensionLoader
想要获取某个扩展的实现,首先要获取到该扩展对应的ExtensionLoader实例。
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) {
//为Extension类型创建ExtensionLoader实例
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
上述方法需要一个Class类型的参数,该参数表示希望加载的扩展点类型,该参数必须是接口,且该接口必须被@SPI注解注释,否则拒绝处理。检查通过之后首先会检查ExtensionLoader缓存中是否已经存在该扩展对应的ExtensionLoader,如果有则直接返回,否则创建一个新的ExtensionLoader负责加载该扩展实现,同时将其缓存起来。所以对于每一个扩展,dubbo中只会有一个对应的ExtensionLoader实例。
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
从ExtensionLoader的构造函数中可以看到,如果要加载的扩展点类型是ExtensionFactory是,objectFactory字段被设置为null。由于ExtensionLoader的使用范围有限(基本上局限在ExtensionLoader中),因此对他做了特殊对待:在需要使用ExtensionFactory的地方,都是通过对应的自适应实现来代替。
objectFactory属性是一个ExtensionFactory类型,ExtensionFactory主要用于加载扩展的实现:
public interface ExtensionFactory {
/**
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
<T> T getExtension(Class<T> type, String name);
}
ExtensionFactory被@SPI注解注释,说明他也是一个扩展点,dubbo内部提供了三个实现类:SpiExtensionFactory 、AdaptiveExtensionFactory以及SpringExtensionFactory,不同的实现可以已不同的方式来完成扩展点实现的加载。
默认的ExtensionFactory实现中,AdaptiveExtensionFactotry被@Adaptive注解,它就是ExtensionFactory对应的自适应扩展实现(每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类),也就是说,所有对ExtensionFactory调用的地方,实际上调用的都是AdpativeExtensionFactory,那么我们看下他的实现代码:
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
// 将所有ExtensionFactory实现保存起来
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
public <T> T getExtension(Class<T> type, String name) {
// 依次遍历各个ExtensionFactory实现的getExtension方法,一旦获取到Extension即返回
// 如果遍历完所有的ExtensionFactory实现均无法找到Extension,则返回null
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
他会遍历当前系统中所有的ExtensionFactory实现来获取指定的扩展实现,获取到扩展实现或遍历完所有的ExtensionFactory实现。这里调用了ExtensionLoader的getSupportedExtensions方法来获取ExtensionFactory的所有实现,又回到了ExtensionLoader类。
方法代码分析
- getExtension
getExtension(name)
-> createExtension(name) #如果无缓存则创建
-> getExtensionClasses().get(name) #获取name对应的扩展类型
-> 实例化扩展类
-> injectExtension(instance) # 扩展点注入
-> instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) #循环遍历所有wrapper实现,实例化wrapper并进行扩展点注入
- getAdaptiveExtension
public T getAdaptiveExtension()
-> createAdaptiveExtension() #如果无缓存则创建
-> getAdaptiveExtensionClass().newInstance() #获取AdaptiveExtensionClass
-> getExtensionClasses() # 加载当前扩展所有实现,看是否有实现被标注为@Adaptive
-> createAdaptiveExtensionClass() #如果没有实现被标注为@Adaptive,则动态创建一个Adaptive实现类
-> createAdaptiveExtensionClassCode() #动态生成实现类java代码
-> compiler.compile(code, classLoader) #动态编译java代码,加载类并实例化
-> injectExtension(instance)
能在本地把代码跑起来,debug状态能更好的跟踪代码的执行,dubbo源代码中提供了非常详细的测试用例,基本涵盖了所有的使用场景,可以本地试试,大有裨益!
com.alibaba.dubbo.common.extensionloader.ExtensionLoaderTest
-
老子《道德经》第七章,老子故里,中国鹿邑。 ↩