概述
这里之所以分析Dubbo的SPI技术,是因为其有如下的优点。
Dubbo SPI的核心优势是作为框架集成三方软件时,具有很强的可扩展性,能够做到用户对于框架内核结构的可替换性。这种扩展机制每个框架的实现都不一样,mybaits给出的实现是通过动态代理以及预先定义好接口并且将内核组件暴露给用户进行改造的方式。Dubbo这种大型的项目给出的实现是SPI的方式直接替换内核组件的实现。
Dubbo SPI机制从功能特性上来讲主要包括一下四个方面
- 扩展点自动包装
- 扩展点自动装配
- 扩展点自适应
- 扩展点自动激活
下面主要是从代码角度来分析这四个方面的实现功能
关于该生成的代码,我们主要要注意如下几个问题:
所有未使用@Adaptive注解标注的接口方法,默认都会抛出异常;
在使用@Adaptive注解标注的方法中,其参数中必须有一个参数类型为URL,或者其某个参数提供了某个方法,该方法可以返回一个URL对象;
在方法的实现中会通过URL对象获取某个参数对应的参数值,如果在接口的@SPI注解中指定了默认值,那么在使用URL对象获取参数值时,如果没有取到,就会使用该默认值;
最后根据获取到的参数值,在ExtensionLoader中获取该参数值对应的服务提供类对象,然后将真正的调用委托给该服务提供类对象进行;
在通过URL对象获取参数时,参数key获取的对应规则是,首先会从@Adaptive注解的参数值中获取,如果该注解没有指定参数名,那么就会默认将目标接口的类名转换为点分形式作为参数名,比如FruitGranter转换为点分形式就是fruit.granter。另外如果Adaptive注解中指定了多个值,则意味着后一个值是默认值,如果注解中的值是protocol时,则按照URL中的protocol中的值获取,直到都没有获取到对应的值,才会去取SPI注解的默认值。注意,这里提到的默认值的意思是兜底值。比如@Adaptive({“key1”, “key2”}) 那个首先尝试用key1去作为key获取对应的值,如果没有,继续会用key2作为默认值。
生成对应的代码如下:
String extName = url.getParameter("key1", url.getParameter("key2", "impl1"));// 其中impl1代表@SPI的默认值