SPI拓展机制(IOC、AOP、自适应拓展)
Dubbo 官方文档 拓展点加载 介绍了Dubbo的SPI拓展机制,总结起来如下:
- 是
JDK SPI
的加强版:
- 只有使用的时候才会实例化拓展点,而摒弃
JDK SPI
一次性实例化所有拓展点- 增加了对IOC、AOP的支持
- 拓展的方法:在扩展类的 jar 包内,放置扩展点配置文件
META-INF/dubbo/接口全限定名
,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。即可被Dubbo自动加载。- 扩展点的特性:
- 扩展点自动装配(IOC):加载扩展点时,扩展点实现类的成员如果为其它扩展点类型,在会自动注入依赖的扩展点;
- 扩展点自动包装:AOP的一种实现方式,为拓展点自动添加一层包装,将某些可拓展的共有逻辑放在包装类(Wrapper)中。调用时,会先调用包装类的逻辑再调用拓展点的内容;
- 扩展点自适应:在拓展点方法执行的时候,根据调用的参数(URL)决定调用的是哪个拓展点实现,而不会在初始化时就直接指定是哪个拓展点;
- 扩展点自动激活:对于集合类拓展点,可以同时加载多个实现。自动激活可以简化配置,且可以编排它们的顺序。
ExtensionLoader
是实现其SPI拓展机制的关键类,Dubbo会为每种类型拓展点都创建有一个ExtensionLoader
实例:
1 | public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { |
其最主要的属性如下:
1 | //所处理的拓展点类型(接口类型) |
对外暴露的最主要的方法如下:
1 | //获取自适应拓展 |
Dubbo初始化时,获取拓展点时一般是调用getActivateExtension
获取自适应拓展点,然后在运行时调用方法时,根据实时的参数URL
确定拓展点实例的name,调用getExtension(name)
获取实例。下面我们依次看这三个实现方法:
getAdaptiveExtension
1 | public T getAdaptiveExtension() { |
上文分析中有三个比较关键的方法getExtensionClasses
、createAdaptiveExtensionClass
、injectExtension
。下面,我们重点来分析它们:
1 | //最终会调用loadExtensionClasses来加载所有type类型的Class |
当没有自适应类时,需要自动拼装自适应类,并编译。
1 | private Class<?> createAdaptiveExtensionClass() { |
创建类后,需要注入属性,injectExtension
方法负责其工作:
1 | private T injectExtension(T instance) { |
getExtension
在getAdapativeExtension
执行中,已经加载了所有的type
拓展类,初始化了type
对应的ExtensionLoader
。
1 | private T createExtension(String name) { |
getActivateExtension
根据条件获取当前扩展可自动激活的实现。比如Filter
、InvokerListener
、ExporterListener
。getActivateExtension
有多个重载函数,最主要的实现在下面这个函数中:
1 | public List<T> getActivateExtension(URL url, String[] values, String group) { |
讲完它的原理,来看几个源码中的例子更好的理解下: