1 加载机制概述
Dubbo具有很好的扩展性,这与其巧妙的运用设计模式、特殊的加载机制密切相关。基于Dubbo SPI 加载机制,让整个框架的接口和具体实现完全解耦,从而奠定了整个框架良好扩展性的基础。Dubbo 几乎所有的功能组件都是基于扩展机制(SPI)实现的。
博主的Honey-Audit审计服务也是利用SPI机制奠定其良好的扩展性基础
1.1扩展点的分类与缓存
Dubbo SPI 可以分为Class 缓存、实例缓存。这两种缓存又能根据扩展类的种类分为普通扩展类、包装扩展类(Wrapper)、自适应扩展类(Adaptive类)等。
- Class 缓存:Dubbo SPI 获取扩展类时,会先从缓存中读取。如果缓存中不存在,则加载配置文件,根据配置把Class缓存到内存中,并不会直接全部实例化。
- 实例缓存:基于性能考虑,Dubbo 框架不仅缓存Class ,也会缓存Class 实例后的对象。每次读取的时候,会先从缓存中读取,如果缓存中读不到,则重新加载并缓存起来。这也是为什么Dubbo SPI相对Java SPI性能上有优势的原因,因为Dubbo SPI 缓存起来的 Class 并不会全部实例化,而是按需实例化并缓存,因此性能会更好。
被缓存的Class和对象实例可以根据不同的特性分为不同的类别:
- 普通扩展类。这是最基础的,配置在SPI 配置文件中的扩展类实现。
注意:自动激活也是属于普通扩展类
- 包装扩展类。这种Wrapper类没有具体的实现,只是做了通用逻辑的抽象并且需要在构造方法中传入一个具体的扩展接口实现。属于Dubbo 的自动包装特性。
- 自适应扩展类。一个扩展接口会有很多实现类,具体使用哪个实现类可以不写死在配置或者代码中,在运行时,通过传入URL中的某些参数动态来确定。这属于扩展点的自适应特性。、
- 其他缓存,如扩展类加载器缓存、扩展名缓存等。
1.2 扩展点的特性
扩展类一共包含四种特性:自动包装、自动加载、自适应和自动激活。
1、自动包装
ExtensionLoader在加载扩展时,如果发现这个扩展类包含其他扩展点作为构造函数的参数,则这个扩展类就会被认为是Wrapper类。这是一种装饰器模式,把通用的抽象逻辑进行封装或对子类进行增强,让子类可以更加专注具体实现。
2、自动加载
除了在构造函数中传入其他扩展实例,我们还经常使用setter方法设置属性值。如果某个扩展类是另一个扩展点类的成员属性,并且拥有setter方法,那么框架也会自动注入对应的扩展点实例。
这里存在一个问题,如果扩展类属性是一个接口,它有多种实现,那么具体注入哪一个实现呢?这涉及第三个特性----自适应
3、自适应
在Dubbo SPI 中,我们使用@Adaptive注解,可以动态地通过URL中的参数来确定要使用哪个具体的实现类。从而解决自动加载中的实例注入问题。
这种自适应根据注解的里值逐个查找,但是只能激活一个具体的实现类,如果需要多个实现类同时被激活,如Filter可以同时有多个过滤器;或者根据不同的条件,同时激活多个实现类,这就涉及最后一个特性----自动激活。
4、自动激活
使用@Activate注解,可以标记对应的扩展点默认被激活启用。该注解还可以通过传入不同的参数,设置扩展点在不同的条件下被自动激活。
2 扩展点注解
2.1 扩展点注解:@SPI
@SPI注解可以使用在类、接口和枚举类上,Dubbo 框架中都是使用在接口上。它的主要作用就是标记这个接口是一个Dubbo SPI 接口,即是一个扩展点,可以有多个不同的内置或用户自定义的实现。运行时需要通过配置找到具体的实现类。
@SPI 注解有一个value属性值,通过这个属性值,我们可以传入不同的参数来设置这个接口的默认实现类。
2.2 扩展点自适应注解:@Adaptive
@Adaptive注解可以标注在类、接口、枚举和方法上。如果标记在接口的方法上,即方法级别注解,则通过参数动态获得实现类。方法级别注解在第一次getExtension时,会自动生成和编译一个动态的Adaptive类(原始类$Adaptive这么一个类),从而达到动态实现类的效果。
当该注解标记在实现类上,则整个实现类会直接作为默认实现,不再自动生成代码。在扩展点接口的多个实现里,只能有一个实现上可以加@Adaptive注解。如果多个实现类有该注解,则会抛出异常。
该注解也可以传入value参数,是一个数组。在初始化Adaptive注解的接口时,会先对传入的URL进行的key值匹配,第一个key没匹配上则匹配第二个,以此类推。直到所有key匹配完毕,如果还没有匹配到,则会使用“驼峰规则”匹配,如果也没匹配到,则抛出异常。
驼峰规则:如果包装类(Wrapper)没有用Adaptive指定key值,则Dubbo会自动把接口名称根据驼峰大小写分开,并用 “.” 符号链接起来,以此作为默认实现类的名称。
2.3 扩展点自动激活注解:@Activate
@Activate 可以标记在类、接口、枚举类和方法上。主要使用在有多个扩展点实现、需要证据不同条件被激活的场景中
参数名 | 效果 |
---|---|
String[] group() | URL中的分组如果匹配则激活,可以设置多个 |
String[] value() | 查找URL中如果含有该key值,则会激活 |
String[] before() | 填写扩展点列表,表示哪些扩展点要在本扩展点之前 |
String[] after() | 填写扩展点列表,表示哪些扩展点要在本扩展点之后 |
int order() | 直接的排序顺序 |
- 本文就到此结束了,我们下文见,谢谢
- github: honey开源系列组件作者