扩展点注解:@SPI

@SPI注解可以使用在类、接口和枚举类上,Dubbo框架中都是使用在接口上。它的主要作用就是标记这个几口是一个Dubbo SPI接口,即是一个扩展点,可以有多个不同的内置或用户定义的实现。运行时需要通过配置找到具体的实现类。

dubbo provider consumer 注解 dubbo的注解_扩展点


可以看到SPI注解有一个value属性,通过这个属性,我们可以传入不同的参数来设置这个接口额默认实现类。例如,我们可以看到Transporter接口使用Netty作为默认实现:

dubbo provider consumer 注解 dubbo的注解_实例化_02


Dubbo中很多地方通过getExtension(Class<T> type, String name)来获取扩展点接口的具体实现,此时会传入Class做校验,判断是否是接口,以及是否有@SPI注解,两者缺一不可。

扩展点自适应注解:@Adaptive

@Adaptive注解可以标记在类、接口、枚举类和方法上,但是在整个Dubbo框架中,只有几个地方使用在类级别上,如AdaptiveExtensionFactory和AdaptiveCompiler,其余都标注在方法上。

如果标注在接口的方法上,即方法级别注解,则可以通过参数动态获得实现类。方法级别注解在第一次getExtension时,会自动生成和编译一个动态的Adaptive类,从而达到动态实现类的效果。

例如:Transporter接口在bind和connect两个方法上添加了@Adaptive注解,如下所示:

dubbo provider consumer 注解 dubbo的注解_实例化_03


Dubbo在初始化扩展点时,会生成一个Transporter#Adaptive类,里面会实现这两个方法,方法里会有一些抽象的通用逻辑,通过@Adaptive中传入的参数,找到并调用真正的实现类。自动生成的代码中实现了很多通用的功能,最终会调用真正的接口实现。

当该注解放在实现类上,则整个实现类会直接作为默认实现,不再自动生成代码清单。在扩展点接口的多个实现里,只能有一个实现上可以加@Adaptive注解。如果多个实现类中都有该注解,则会抛出异常:More than 1 adaptive class found

dubbo provider consumer 注解 dubbo的注解_扩展点_04

该注解也可以传入value参数,是一个数组。Adaptive可以传入多个key值,在初始化Adaptive注解的接口时,会先对传入的URL进行key值匹配,第一个key没匹配上则匹配第二个,以此类推。直到所有的key匹配完毕,如果还没有匹配到,则会使用"驼峰规则"匹配,如果也没有匹配到,则会抛出IllegalStateException异常。

驼峰规则:
如果包装类(Wrapper)没有用Adaptive指定key值,则Dubbo会自动把接口名称根据驼峰大小写分开,并用"."符号连接起来,以此来作为默认实现类的名称,如org.apache.dubbo.xxx.YyyInvokerWrapper中的YyyInvokerWrapper会被转换为yyy.invoker.warpper

为什么有些实现类上会标注@Adaptive?
放在实现类上,主要是为了直接固定对应的实现而不需要动态生成代码实现,就像策略模式直接确定实现类。

在代码中的实现方式是:ExtensionLoader中会缓存两个与@Adaptive有关的对象:

  1. 一个缓存在cachedAdaptiveClass中,即Adaptive具体实现类的Class类型;
  2. 另外一个缓存在cachedAdaptiveInstance中,即Class的具体实例化对象;

在扩展点初始化时,如果发现实现类有@Adaptive注解,则直接赋值给cachedAdaptiveClass,后续实例化类的时候,就不会再动态生成代码,直接实例化cachedAdaptiveClass,并把实例缓存到cachedAdativeInstance中。

如果注解在接口方法上,则会根据参数,动态获得扩展点的实现,会生成Adaptive类,再缓存到cachedAdaptiveInstance中。

扩展点自动激活注解:@Activate

@Activate可以标记在类、接口、枚举类和方法上。主要使用在有多个扩展点实现、需要根据不同条件被激活的场景中,如Filter需要多个同时激活,因为每个Filter实现的是不同的功能。

@Activate可传入的参数:

参数名

效果

String[] group()

URL中的分组如果匹配则激活,则可以设置多个

String[] value()

查找URL中如果含有该key值,则会激活

String[] before()

填写扩展点列表,表示那些扩展点要在本扩展点之前

String[] after()

同上,表示哪些需要在本扩展点之后

int order()

整型,直接的排序信息