dubbo的扩展机制比较多,有@Activate,@Adaptive,@SPI,Wrapper等方式扩展功能。
每一种方式的适用场景是不太一样的,在此分别予以解释。
- @Activate
一般用于过程中动态装载,根据group,value与order的值动态组装一组实例为调用过程赋能。其通过ExtensionLoader的getActivateExtension方法获取指定条件下的一组实例。但是这里有一点需要注意,该注解支持的目标有类型,方法。但ExtensionLoader在实际执行loadClass时,仅根据class上的注解标注来进行cache处理。故该能力实际仅能用于在类上标注。
- @Adaptive
功能适配点,用于扩展某一个功能定义的新的实现。该能力用于根据URL中key的值定义动态适配执行的实现。该注解支持类上&方法上标注,在方法上标注时,会基于@SPI标注接口动态创建一个实现,在该实现中,标注了@Adaptive的方法会根据指定key的value作为具体实现的名称去@SPI标注接口的实现map中寻找具体实现,然后基于该实现发起执行。未标注@Adaptive注解的方法,会实现为不支持此操作,抛出相应异常。
在类上标注时,会使用此类作为该@SPI标注接口的适配类,负责具体的适配能力。
- @SPI
扩展点,用于声明具体的扩展点,可以顺便指定默认实现。可以通过该方式扩展一个新的能力定义,并结合@Activate&@Adaptive注解,动态适配调用上下文。
在dubbo中,其SPI机制和默认SPI不太一样,其定义了多个配置的路径,会分别从多个路径装载指定接口的扩展定义。如果装载失败,会抛出具体的装载异常。
基本介绍了这些注解后,有一个都会涉及到的类ExtensionLoader是驱动这些注解逻辑的核心。
其主要能力是从定义的路径下装载指定接口的文件,并将其内容解析成map,按名称&实例关系进行管理。在这个过程中,会识别@Activate&@Adaptive注解,并做好相应的缓存处理。在外部发起具体调用时,会根据是Activate,还是Adaptive,结合相应的参数选择具体的实现返回。在初始化class时,其支持从Spring容器中获取bean并做注入处理。其IoC原理和常用的依赖注入不太一样,并不能通过Spring相关的注解注入,而是需要通过spring的ApplicationContext进行依赖查找来做注入操作。
- Wrapper
通过在SPI路径声明接口的Wrapper的实现class,同时约定实例化的方式是通过指定接口类型的构造函数的方式,可以实现在ExtensionLoader.getExtension时,对任意具体的实例自动做Wrapper包装。这个能力有点类似AOP,可以提供自动全面的扩展能力。
因为Dubbo的调用链路的初始化,会在spring的所有bean初始化完成后再开始,故不会存在注入一个异常bean的情况。