org.apache.dubbo.common.extension.ExtensionLoader#getExtensionClasses
- Dubbo扩展点加载机制的核心方法,负责从配置文件中读取并解析所有的扩展点实现类。
- 理解Dubbo SPI机制的核心入口
private Map<String, Class<?>> getExtensionClasses() {
// 从缓存中读取已加载的扩展类
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
loadExtensionClassesLock.lock();
try {
classes = cachedClasses.get();
if (classes == null) {
try {
// 双重检测锁,确保只加载一次
classes = loadExtensionClasses();
} catch (InterruptedException e) {
logger.error(
COMMON_ERROR_LOAD_EXTENSION,
"",
"",
"Exception occurred when loading extension class (interface: " + type + ")",
e);
throw new IllegalStateException(
"Exception occurred when loading extension class (interface: " + type + ")", e);
}
cachedClasses.set(classes);
}
} finally {
loadExtensionClassesLock.unlock();
}
}
return classes;
}
org.apache.dubbo.common.extension.ExtensionLoader#loadExtensionClasses
- 加载扩展类
private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {
// 检查扩展加载器是否已被销毁,防止在应用关闭过程中继续加载扩展点
checkDestroyed();
// 缓存默认扩展点名称(通过 @SPI 注解指定)
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
// 遍历所有加载策略
// LoadingStrategy:用于定义扩展点加载策略
// getDirectory():返回扩展实现的配置文件所在目录(如 META-INF/dubbo/)
// getPriority():定义加载策略的优先级,数值越小优先级越高
// 默认实现类
// DubboInternalLoadingStrategy:加载Dubbo内部组件,路径为 META-INF/dubbo/internal/
// DubboLoadingStrategy:加载用户自定义扩展,路径为 META-INF/dubbo/
// ServicesLoadingStrategy:兼容 JDK SPI 标准,路径为 META-INF/services/
for (LoadingStrategy strategy : strategies) {
// 从当前策略指定的路径加载扩展类
loadDirectory(extensionClasses, strategy, type.getName());
// 兼容旧版本的 ExtensionFactory 实现
if (this.type == ExtensionInjector.class) {
loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
}
}
return extensionClasses;
}
org.apache.dubbo.common.extension.ExtensionLoader#loadDirectory
- 从特定目录加载扩展类的配置文件,并将其映射关系存储到
extensionClasses
中 - 为了兼容从
com.alibaba
迁移到org.apache
的类路径变更,它会尝试加载旧路径下的同名类
private void loadDirectory(Map<String, Class<?>> extensionClasses, LoadingStrategy strategy, String type)
throws InterruptedException {
// 实际执行加载逻辑的内部方法,它会根据 strategy 提供的目录(如 META-INF/dubbo/)读取配置文件,并将扩展名与实现类的映射存入 extensionClasses
loadDirectoryInternal(extensionClasses, strategy, type);
// 用于判断是否启用 Dubbo 2.x 兼容性模式
if (Dubbo2CompactUtils.isEnabled()) {
try {
// 将类路径中的 org.apache 替换为 com.alibaba(例如 org.apache.dubbo.xxx → com.alibaba.dubbo.xxx)
String oldType = type.replace("org.apache", "com.alibaba");
if (oldType.equals(type)) {
return;
}
// 通过 ClassUtils.forName(oldType) 检查旧类是否存在,若不存在则跳过加载
ClassUtils.forName(oldType);
// 若旧类存在,调用 loadDirectoryInternal 加载旧路径下的配置文件,避免因类路径变更导致的兼容性问题。
loadDirectoryInternal(extensionClasses, strategy, oldType);
} catch (ClassNotFoundException classNotFoundException) {
}
}
}
org.apache.dubbo.common.extension.ExtensionLoader#loadDirectoryInternal
参数
extensionClasses
: 用于存储加载的扩展类的映射,键为扩展名,值为对应的 Class 对象loadingStrategy
: 加载策略,包含目录、是否覆盖、包含 / 排除的包等配置type
: 扩展点类型的名称
用处
- 多种类加载器的处理
- 特殊 SPI 加载策略的定制
- 范围模型类加载器的支持
- 资源加载的错误处理
private void loadDirectoryInternal(
Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type)
throws InterruptedException {
// 构建文件名并初始化类加载器列表
String fileName = loadingStrategy.directory() + type;
try {
List<ClassLoader> classLoadersToLoad = new LinkedList<>();
// 优先处理扩展类加载器
// 如果加载策略优先使用扩展类加载器,则将扩展加载器本身的类加载器加入列表
if (loadingStrategy.preferExtensionClassLoader()) {
ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
classLoadersToLoad.add(extensionLoaderClassLoader);
}
}
// 处理特殊 SPI 加载策略
// 如果存在针对该类型的特殊加载策略,则检查当前加载策略名称是否匹配。若匹配则清空类加载器列表,仅使用扩展类加载器。
if (specialSPILoadingStrategyMap.containsKey(type)) {
String internalDirectoryType = specialSPILoadingStrategyMap.get(type);
// skip to load spi when name don't match
if (!LoadingStrategy.ALL.equals(internalDirectoryType)
&& !internalDirectoryType.equals(loadingStrategy.getName())) {
return;
}
classLoadersToLoad.clear();
classLoadersToLoad.add(ExtensionLoader.class.getClassLoader());
} else {
// 处理范围模型类加载器
// 如果没有特殊加载策略,则获取范围模型的类加载器。若类加载器集合为空,则直接从系统类加载器加载资源;否则将这些类加载器添加到待处理列表。
Set<ClassLoader> classLoaders = scopeModel.getClassLoaders();
if (CollectionUtils.isEmpty(classLoaders)) {
Enumeration<java.net.URL> resources = ClassLoader.getSystemResources(fileName);
if (resources != null) {
while (resources.hasMoreElements()) {
loadResource(
extensionClasses,
null,
resources.nextElement(),
loadingStrategy.overridden(),
loadingStrategy.includedPackages(),
loadingStrategy.excludedPackages(),
loadingStrategy.onlyExtensionClassLoaderPackages());
}
}
} else {
classLoadersToLoad.addAll(classLoaders);
}
}
// 加载并处理资源
// 使用类加载器资源加载器加载所有匹配的资源文件,然后遍历每个类加载器及其对应的资源 URL,调用 loadFromClass 方法处理这些资源。
Map<ClassLoader, Set<java.net.URL>> resources =
ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);
resources.forEach(((classLoader, urls) -> {
loadFromClass(
extensionClasses,
loadingStrategy.overridden(),
urls,
classLoader,
loadingStrategy.includedPackages(),
loadingStrategy.excludedPackages(),
loadingStrategy.onlyExtensionClassLoaderPackages());
}));
} catch (InterruptedException e) {
throw e;
} catch (Throwable t) {
logger.error(
COMMON_ERROR_LOAD_EXTENSION,
"",
"",
"Exception occurred when loading extension class (interface: " + type + ", description file: "
+ fileName + ").",
t);
}
}