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