Dubbo SPI 加载逻辑
SPI 配置的加载
Dubbo 通过 loadExtensionClasses 方法加载 SPI。
/**
* synchronized in getExtensionClasses
*/
private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {
checkDestroyed();
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy, type.getName());
// compatible with old ExtensionFactory
if (this.type == ExtensionInjector.class) {
loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
}
}
return extensionClasses;
}
通过 strategies 加载扩展点集合,三个 LoadingStrategy 指定的目录分别为 ‘META-INF/dubbo/internal/, META-INF/dubbo/, META-INF/services/’。其中,META-INF/dubbo/internal/ 存放的是 Dubbo 内置的一些扩展点,META-INF/services/ 存放的是 Dubbo 自身的一些业务逻辑所需要的一些扩展点,而 META-INF/dubbo/ 存放的是上层业务系统自身的一些定制 Dubbo 的相关扩展点。
该方法返回给 getExtensionClasses, getExtensionClasses 将加载的 SPI 类对象缓存起来。
SPI 扩展类实例的获取
通过 ExtensionAccessor.getExtensionAccessor 方法获取 ExtensionAccessor,然后从 ExtensionAccessor 获取 SPI 扩展类的实例。
// 获取 ExtensionAccessor 实例
ExtensionAccessor extensionAccessor = ExtensionAccessor.getExtensionAccessor();
// 通过 ExtensionAccessor 获取扩展加载器
ExtensionLoader<HelloService> extensionLoader = extensionAccessor.getExtensionLoader(HelloService.class);
ExtensionAccessor 调用 ExtensionDirector 获取 ExtensionLoader:
public interface ExtensionAccessor {
ExtensionDirector getExtensionDirector();
default <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
return getExtensionDirector().getExtensionLoader(type);
}
...
}
ExtensionDirector 用于管理和协调多个 ExtensionLoader,其 getExtensionLoader 方法实现如下:
@Override
@SuppressWarnings("unchecked")
public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
checkDestroyed();
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
}
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type
+ ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
// 1. find in local cache
ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
ExtensionScope scope = extensionScopeMap.get(type);
if (scope == null) {
SPI annotation = type.getAnnotation(SPI.class);
scope = annotation.scope();
extensionScopeMap.put(type, scope);
}
if (loader == null && scope == ExtensionScope.SELF) {
// create an instance in self scope
loader = createExtensionLoader0(type);
}
// 2. find in parent
if (loader == null) {
if (this.parent != null) {
loader = this.parent.getExtensionLoader(type);
}
}
// 3. create it
if (loader == null) {
loader = createExtensionLoader(type);
}
return loader;
}
ExtensionDirector 首先在自身缓存查找 ExtensionLoader,然后在 parent 查找 ExtensionLoader,都找不到时则通过 type 创建。
一个 ExtensionLoader 对应一个 SPI 接口,而每个 SPI 接口可以有多个扩展实现类,所以 ExtensionLoader 和 Extension 的关系是一对多。以下示例提供了多个 LoadBalance 扩展实现类,通过 getExtension 和扩展类的名称获取 Extension。
import org.apache.dubbo.common.extension.ExtensionLoader;
// 定义SPI接口
interface LoadBalance {
String select();
}
// 实现类1:随机负载均衡
class RandomLoadBalance implements LoadBalance {
@Override
public String select() {
return "Random selection";
}
}
// 实现类2:轮询负载均衡
class RoundRobinLoadBalance implements LoadBalance {
@Override
public String select() {
return "Round-robin selection";
}
}
public class Main {
public static void main(String[] args) {
// 获取LoadBalance接口对应的ExtensionLoader
ExtensionLoader<LoadBalance> extensionLoader = ExtensionLoader.getExtensionLoader(LoadBalance.class);
// 获取不同的扩展实现
LoadBalance randomLoadBalance = extensionLoader.getExtension("random");
LoadBalance roundRobinLoadBalance = extensionLoader.getExtension("roundrobin");
}
}
在 ExtensionLoader 中加载 Extension 的逻辑如下:
getExtension -> createExtension -> createExtensionInstance -> InstantiationStrategy.instantiate
InstantiationStrategy.instantiate 将一个类的对象实例化:
- 找到合适的构造器
- 从 ScopeModel 拿到构造参数
- 通过类构造器实例化并返回
ExtensionLoader 与 Extension
为什么不一股脑加载出 Extension,为什么需要 ExtensionLoader?
1. 解耦与模块化设计
分离关注点:ExtensionLoader 承担了扩展加载的具体逻辑,将扩展加载的过程与使用扩展的代码分离开来。这样一来,使用扩展的代码不需要关心扩展是如何从配置文件中加载出来的,只需要通过 ExtensionLoader 获取所需的扩展实例即可,符合单一职责原则,提高了代码的可维护性和可扩展性。
便于扩展和维护:当需要修改扩展加载的规则或者支持新的配置文件格式时,只需要修改 ExtensionLoader 的实现,而不会影响到使用扩展的代码。例如,后续如果要支持从数据库中加载扩展信息,只需要在 ExtensionLoader 中添加相应的逻辑。
2. 配置解析与管理
配置文件解析:Dubbo 的扩展配置通常存储在 META - INF/dubbo 或 META - INF/services 目录下的文件中,ExtensionLoader 负责解析这些配置文件,提取出扩展接口与实现类的映射关系。例如,它会读取文件内容,将配置信息解析成 Map 结构,方便后续查找和使用。
配置缓存:ExtensionLoader 会对解析后的配置信息进行缓存,避免重复解析配置文件,提高扩展加载的性能。当多次获取同一个扩展接口的扩展实现时,直接从缓存中获取配置信息,而不需要再次读取和解析配置文件。
3. 实例化与生命周期管理
实例化扩展:ExtensionLoader 负责根据配置信息实例化扩展类。它会处理扩展类的构造函数注入、依赖注入等问题,确保扩展类能够正确地被创建。例如,如果扩展类的构造函数需要传入其他扩展实例,ExtensionLoader 会先获取这些依赖的扩展实例,然后再实例化该扩展类。
生命周期管理:ExtensionLoader 可以管理扩展实例的生命周期,包括初始化、销毁等操作。在扩展实例创建后,ExtensionLoader 可以调用扩展类的初始化方法;在扩展实例不再使用时,也可以调用相应的销毁方法,确保资源的正确释放。
4. 自适应扩展与包装器处理
自适应扩展:Dubbo 支持自适应扩展机制,ExtensionLoader 负责实现自适应扩展的逻辑。自适应扩展可以根据运行时的参数动态选择合适的扩展实现,而不需要在代码中硬编码扩展的名称。ExtensionLoader 会生成自适应扩展的代理类,根据实际情况调用不同的扩展实现。
包装器处理:当获取扩展实例时,ExtensionLoader 会自动将包装器应用到 Extension 实例上,实现对扩展功能的增强。
Extension 访问器 ExtensionAccessor
ExtensionAccessor 是 Extension 的统一访问器。
- 用于获取扩展加载管理器ExtensionDirector对象
- 获取扩展对象 ExtensionLoader
- 根据扩展名字获取具体扩展对象
- 获取自适应扩展对象
- 获取默认扩展对象
模块领域模型 ScopeModel
ScopeModel
ScopeModel 是为了实现:
- 让 Dubbo 支持多应用的部署,这块一些大企业有诉求
- 从架构设计上,解决静态属性资源共享、清理的问题
- 分层模型将应用的管理和服务的管理分开
ScopeModel 类是模型对象的公共抽象父类型
- 内部 id 用于表示模型树的层次结构
- 公共模型名称,可以被用户设置
- 描述信息
- 类加载器管理
- 父模型管理 parent
- 当前模型的所属域 ExtensionScope 有: FRAMEWORK (框架),APPLICATION (应用),MODULE (模块),SELF (自给自足,为每个作用域创建一个实例,用于特殊的 SPI 扩展,如 ExtensionInjector)
- 具体的扩展加载程序管理器对象的管理: ExtensionDirector
- 域 Bean 工厂管理,一个内部共享的 Bean 工厂 ScopeBeanFactory
FrameworkModel
dubbo 框架模型,可与多个应用程序共享
- FrameworkModel 实例对象集合,allInstances
- 所有 ApplicationModel 实例对象集合,applicationModels
- 发布的 ApplicationModel 实例对象集合 pubApplicationModels
- 框架的服务存储库 FrameworkServiceRepository 类型对象(数据存储在内存中)
- 内部的应用程序模型对象 internalApplicationModel
ApplicationModel
ApplicationModel 表示正在使用 Dubbo 的应用程序,并存储基本元数据信息,以便在 RPC 调用过程中使用。ApplicationModel 包括许多关于发布服务的 ProviderModel 和许多关于订阅服务的 Consumer Model。
- ExtensionLoader、DubboBootstrap 和这个类目前被设计为单例或静态(本身完全静态或使用一些静态字段)。因此,从它们返回的实例属于流程范围。如果想在一个进程中支持多个 dubbo 服务器,可能需要重构这三个类。
- 所有 ModuleModel 实例对象集合 moduleModels
- 发布的 ModuleModel 实例对象集合 pubModuleModels
- 环境信息 Environment 实例对象 environment
- 配置管理 ConfigManager 实例对象 configManager
- 服务存储库 ServiceRepository 实例对象 serviceRepository
- 应用程序部署器 ApplicationDeployer 实例对象 deployer
- 所属框架 FrameworkModel 实例对象 frameworkModel
- 内部的模块模型 ModuleModel 实例对象 internalModule
- 默认的模块模型 ModuleModel 实例对象 defaultModule
Module Model
ModuleModel 是服务模块的模型。
- 所属应用程序模型 ApplicationModel 实例对象 applicationModel
- 模块环境信息 ModuleEnvironment 实例对象 moduleEnvironment
- 模块服务存储库 ModuleServiceRepository 实例对象 serviceRepository
- 模块的服务配置管理 ModuleConfigManager 实例对象 moduleConfigManager
- 模块部署器 ModuleDeployer 实例对象 deployer 用于导出和引用服务