当前位置: 首页 > news >正文

DubboSPI

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/)读取配置文件,并将扩展名与实现类的映射存入 extensionClassesloadDirectoryInternal(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 matchif (!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);}
}
http://www.lqws.cn/news/479233.html

相关文章:

  • 如何在FastAPI中玩转GitHub认证,让用户一键登录?
  • 安卓对外发布工程源码:怎么做到仅UI层公布
  • Openwrt基本初始化(安装中文包,磁盘扩容)
  • MATLAB的.mat文件
  • Python 商务数据分析—— NumPy 学习笔记Ⅱ
  • Spark教程1:Spark基础介绍
  • 爬虫入门练习(文字数据的爬取)
  • Vue3解析Spring Boot ResponseEntity
  • “MOOOA多目标鱼鹰算法在无人机多目标路径规划
  • 2025国际无人机应用及防控大会四大技术专题深度解析
  • 算法-动态规划-钢条切割问题
  • 理解后端开发中的中间件(以gin框架为例)
  • Android14 app被冻结导致进程间通信失败
  • 一键打包利器:gopack - 极简Go程序编译与压缩工具
  • 解决OSS存储桶未创建导致的XML错误
  • 【CBAP50技术手册】#44 Survey and Questionnaire(问卷调研):BA(业务分析师)的“信息入口”
  • 反无人机系统:技术利刃如何守护低空安全?
  • 【2025年软考中级】第三章数据结构3.4 数组与矩阵
  • 计算鱼眼相机的内参矩阵和畸变系数方法
  • 开源 python 应用 开发(二)基于pyautogui、open cv 视觉识别的工具自动化
  • linux VFS简介
  • Java面试复习:基础、面向对象、多线程、JVM与Spring核心考点
  • 历史数据分析——山西汾酒
  • Linux下QGIS二次开发环境搭建
  • React 核心原理与Fiber架构
  • 基于python代码的通过爬虫方式实现TK下载视频(2025年6月)
  • 华为OD机考-用户调度问题-DP(JAVA 2025B卷)
  • React中的useEffect详解
  • PyTorch中的permute, transpose, view, reshape和flatten函数详解(已解决)
  • python的高校教师资源管理系统