概述
来源:
Dubbo的扩展点加载从JDK标准的SPI(Service Provider Interface)扩展点发现机制加强而来。
Dubbo改进了JDK标准的SPI的以下问题:
JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK标准的ScriptEngine,通过getName();获取脚本类型的名称,但如果RubyScriptEngine因为所依赖的jruby.jar不存在,导致RubyScriptEngine类加载失败,这个失败原因被吃掉了,和ruby对应不起来,当用户执行ruby脚本时,会报不支持ruby,而不是真正失败的原因。
增加了对扩展点IoC和AOP的支持,一个扩展点可以直接setter注入其它扩展点。
约定:
在扩展类的jar包内,放置扩展点配置文件:META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。
(注意:这里的配置文件是放在你自己的jar包内,不是dubbo本身的jar包内,Dubbo会全ClassPath扫描所有jar包内同名的这个文件,然后进行合并)
扩展Dubbo的协议示例:
在协议的实现jar包内放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:
xxx=com.alibaba.xxx.XxxProtocol
实现内容:
package com.alibaba.xxx;
import com.alibaba.dubbo.rpc.Protocol;
public class XxxProtocol implemenets Protocol {
// ...
}
注意: 扩展点使用单一实例加载(请确保扩展实现的线程安全性),Cache在ExtensionLoader中
特性
- 扩展点自动包装
- 扩展点自动装配
- 扩展点自适应
- 扩展点自动激活
相关文档可以参考dubbo的官方文档 ,本文主要通过分析相关的源代码来体会dubbo的扩展点框架提供的特性。
源码分析
dubbo的扩展点框架主要位于这个包下:
com.alibaba.dubbo.common.extension
大概结构如下:
com.alibaba.dubbo.common.extension
|
|--factory
| |--AdaptiveExtensionFactory #稍后解释
| |--SpiExtensionFactory #稍后解释
|
|--support
| |--ActivateComparator
|
|--Activate #自动激活加载扩展的注解
|--Adaptive #自适应扩展点的注解
|--ExtensionFactory #扩展点对象生成工厂接口
|--ExtensionLoader #扩展点加载器,扩展点的查找,校验,加载等核心逻辑的实现类
|--SPI #扩展点注解
其中最核心的类就是ExtensionLoader
,几乎所有特性都在这个类中实现,先来看下他的结构:
ExtensionLoader
没有提供public
的构造方法,但是提供了一个public static
的getExtensionLoader
,这个方法就是获取ExtensionLoader
实例的工厂方法。其public
成员方法中有三个比较重要的方法:
- getActivateExtension :根据条件获取当前扩展可自动激活的实现
- getExtension : 根据名称获取当前扩展的指定实现
- getAdaptiveExtension : 获取当前扩展的自适应实现
这三个方法将会是我们重点关注的方法;* 每一个ExtensionLoader
实例仅负责加载特定SPI
扩展的实现*。因此想要获取某个扩展的实现,首先要获取到该扩展对应的ExtensionLoader
实例,下面我们就来看一下获取ExtensionLoader
实例的工厂方法getExtensionLoader
:
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
if(!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if(!withExtensionAnnotation(type)) { // 只接受使用@SPI注解注释的接口类型
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
// 先从静态缓存中获取对应的ExtensionLoader实例
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); // 为Extension类型创建ExtensionLoader实例,并放入静态缓存
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
该方法需要一个Class
类型的参数,该参数表示希望加载的扩展点类型,该参数必须是接口,且该接口必须被@SPI
注解注释,否则拒绝处理。检查通过之后首先会检查ExtensionLoader缓存中是否已经存在该扩展对应的ExtensionLoader
,如果有则直接返回,否则创建一个新的ExtensionLoader
负责加载该扩展实现,同时将其缓存起来。可以看到对于每一个扩展,dubbo中只会有一个对应的ExtensionLoader
实例。
接下来看下ExtensionLoader
的私有构造函数:
private ExtensionLoader(Class<?> type) {
this.type = type;
// 如果扩展类型是ExtensionFactory,那么则设置为null
// 这里通过getAdaptiveExtension方法获取一个运行时自适应的扩展类型(每个Extension只能有一个@Adaptive类型的实现,如果没有dubbo会动态生成一个类)
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
这里保存了对应的扩展类型,并且设置了一个额外的objectFactory
属性,他是一个ExtensionFactory
类型,ExtensionFactory
主要用于加载扩展的实现:
@SPI
public interface ExtensionFactory {
/**
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
<T> T getExtension(Class<T> type, String name);
}
同时ExtensionFactory
也被@SPI
注解注释,说明他也是一个扩展点,从前面com.alibaba.dubbo.common.extension
包的结构图中可以看到,dubbo内部提供了两个实现类:SpiExtensionFactory
和 AdaptiveExtensionFactory
,实际上还有一个SpringExtensionFactory
,不同的实现可以已不同的方式来完成扩展点实现的加载,这块稍后再来学习。从ExtensionLoader
的构造函数中可以看到,如果要加载的扩展点类型是ExtensionFactory
是,object
字段被设置为null。由于ExtensionLoader
的使用范围有限(基本上局限在ExtensionLoader
中),因此对他做了特殊对待:在需要使用ExtensionFactory
的地方,都是通过对应的自适应实现来代替。
默认的ExtensionFactory
实现中,AdaptiveExtensionFactotry
被@Adaptive
注解注释,也就是它就是ExtensionFactory
对应的自适应扩展实现(每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive
注释的,那么dubbo会动态生成一个自适应实现类),也就是说,所有对ExtensionFactory
调用的地方,实际上调用的都是AdpativeExtensionFactory
,那么我们看下他的实现代码:
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) { // 将所有ExtensionFactory实现保存起来
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
public</