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

dubbo拓展点机制(和对JDK SPI机制的优化)

根据dubbo官网描述,dubbo自定义了一套服务发现机制,和JDK的SPI机制相比较:

Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。
Dubbo 改进了 JDK 标准的 SPI 的以下问题:

  1. JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  2. 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName()
    获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致
    RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持
    ruby,而不是真正失败的原因。
  3. 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

具体分析,JDK的SPI机制发现服务的路径为META-INF/services/路径下的文件,文件名为接口全限定名,里面每一行为接口的实现;
JDK中加载SPI的方式为:使用类ServiceLoader.load加载路径META-INF/services/下的服务;

而在dubbo中,定义了三种加载服务的策略,分别对应不同的加载位置,都是org.apache.dubbo.common.extension.LoadingStrategy接口的实现:

● org.apache.dubbo.common.extension.DubboInternalLoadingStrategy:加载dubbo内部的服务,加载路径为:META-INF/dubbo/internal/;
● org.apache.dubbo.common.extension.DubboLoadingStrategy:加载自定义的dubbo服务,加载路径为:META-INF/dubbo/;
● org.apache.dubbo.common.extension.ServicesLoadingStrategy:使用JDK原生的加载机制,加载路径为:META-INF/services/;

dubbo在加载拓展点的时候,是遍历所有的LoadingStrategy服务实现,在loadDirectory方法中用当前策略的加载路径+要加载的接口全限定名作为资源文件路径,进行每一行内容的解析:

        for (LoadingStrategy strategy : strategies) {
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(),
                    strategy.overridden(), strategy.excludedPackages());
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"),
                    strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

dubbo获取拓展点服务-示例代码

与JDK的SPI文件内容格式不同的是,dubbo的自定义服务文件中的内容为key=value的形式:例如有接口:io.itaiit.spi.ResourceLoader,和接口的实现:

  • io.itaiit.spi.impl.ResourceLoaderImpl;
  • io.itaiit.spi.impl.ResourceLoaderImpl2;

META-INF/dubbo/io.itaiit.spi.ResourceLoader文件中的内容为:

xmlloader=io.itaiit.spi.impl.ResourceLoaderImpl
xmlloader2=io.itaiit.spi.impl.ResourceLoaderImpl2

获取服务代码示例:

@Slf4j
public class AppTest {
    @Test
    void test01() {
        ExtensionLoader<ResourceLoader> extensionLoader = ExtensionLoader.getExtensionLoader(ResourceLoader.class);
        ResourceLoader loader1 = extensionLoader.getExtension("xmlloader");
        log.info(loader1.toString());
    }
}

输出为:
19:06:44.617 [main] INFO io.itaiit.AppTest - io.itaiit.spi.impl.ResourceLoaderImpl2@11dc3715

针对于三个优化的理解

  1. 类似于懒加载实例化;
    dubbo通过带泛型的ExtensionLoader类,加载并解析与泛型类型相对应的资源文件,当声明了一个ExtensionLoader对象的时候,只是加载了所有实现类的Class对象,并没有创建实例对象;当通过getExtension(String name)获得具体的实现的时候,才会创建真正的实例对象;

    并且使用与JDK SPI默认加载路径不同的路径,来存放自定义的服务发现信息,与JDK的SPI机制互不干扰;

  2. 易读的异常信息;
    加载和实例化过程中,完善了异常的提示信息:catch中抛出异常的完善,例如:

    throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                        type + ") couldn't be instantiated: " + t.getMessage(), t);
    
  3. dubbo的服务之间可以自动注入;
    dubbo提供了两种自动注入的方式:
    - byName;(默认)
    - byType;
    对于需要注入的参数,使用的注解是:org.apache.dubbo.common.extension.Inject

细节补充

  1. 服务定义文件中的服务可以设置别名:key中可以用,分隔,设置多个名字:
    xmlloader2, aliasname=io.itaiit.spi.impl.ResourceLoaderImpl2
  2. 方法ExtensionLoader.getLoadedExtension(),会从缓存中获取已经加载过的服务实例,如果没有加载过,则返回null;

相关文章:

  • HTML常用标签积累
  • 【一起学SQLite】--SQLite中一些与众不同的特性?(2-1)
  • A+文档丨Azure MySQL 数据库高可用性解析
  • 【Python基础】Numpy:切片和索引操作
  • 【PAT甲级】1004 Counting Leaves
  • 【Vue】vue基础学习笔记
  • 边缘检测算子之间的优劣
  • 在软件测试摸爬滚打了8年,失业半年了。offer你在哪儿呀!
  • 15分钟了解sql注入(一) union注入
  • 基于混沌映射与差分进化自适应教与学优化算法-附代码
  • nginx基本使用一 ——————反向代理、负载均衡
  • 通讯录管理系统精解
  • 线上展厅表现形式 广州商迪
  • CDH 07Cloudera Manager freeIPA安装配置(markdown新版)
  • 22-09-23 西安 谷粒商城(05)CompletableFuture异步编排、nginx实现页面静态化
  • [NodeJS] 关于Buffer
  • 【翻译】babel对TC39装饰器草案的实现
  • JavaScript实现分页效果
  • Octave 入门
  • Vue学习第二天
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 浮现式设计
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 理解在java “”i=i++;”所发生的事情
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 如何设计一个微型分布式架构?
  • 设计模式走一遍---观察者模式
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • mysql面试题分组并合并列
  • ​LeetCode解法汇总518. 零钱兑换 II
  • (13)Hive调优——动态分区导致的小文件问题
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (二)hibernate配置管理
  • (附源码)计算机毕业设计大学生兼职系统
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (四)Linux Shell编程——输入输出重定向
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转)菜鸟学数据库(三)——存储过程
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .gitignore
  • .libPaths()设置包加载目录
  • .NET CLR Hosting 简介
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • [2024] 十大免费电脑数据恢复软件——轻松恢复电脑上已删除文件
  • [android] 天气app布局练习
  • [Android]一个简单使用Handler做Timer的例子
  • [AutoSar]BSW_OS 02 Autosar OS_STACK
  • [BUAA软工]第一次博客作业---阅读《构建之法》
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)