dubbo源码实践-SPI扩展

news2024/9/24 7:20:01

1 概述

SPI的官方文档说明:Dubbo SPI | Apache Dubbo

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。

dubbo通过SPI完成的功能:

1)程序运行时切换实现类

2)支持用户扩展,我们可以定义自己的实现类,并且使用该类

3)依赖注入,实现类依赖的属性自动注入,类似spring的依赖注入。

4)支持AOP功能,支持类似spring的AOP功能,在dubbo中AOP功能的类要求以Wrapper名字结尾类。

功能举例

2.0 项目准备

使用官方例子,这里直接上代码了。maven工程,保证有以下4个文件。

1个接口Robot,2个实现类Bumblebee、OptimusPrime,1个配置文件org.example.test.exLoader.Robot。

1个接口Robot

package org.example.test.exLoader;
import org.apache.dubbo.common.extension.SPI;
/**
 * 机器人
 */
@SPI
public interface Robot {
    void sayHello();
}

2个实现类

package org.example.test.exLoader;
/**
 * 大黄蜂
 */
public class Bumblebee implements Robot{
    @Override
    public void sayHello() {
        System.out.println("Hello, I am Bumblebee.");
    }
}
package org.example.test.exLoader;
/**
 * 擎天柱
 */
public class OptimusPrime implements Robot{
    @Override
    public void sayHello() {
        System.out.println("Hello, I am Optimus Prime.");
    }
}

1个配置文件

文件:resources/META-INF/dubbo/org.example.test.exLoader.Robot。

等号前面的是名字(文件内唯一, 代码中靠名字来找到对应的类),等号后面的是实现类,文件名是接口的全名。

optimusPrime = org.example.test.exLoader.OptimusPrime
bumblebee = org.example.test.exLoader.Bumblebee

maven依赖

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.8</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.25.0-GA</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

2.1 程序运行时切换实现类

package org.example.test.exLoader;
import org.apache.dubbo.common.extension.ExtensionLoader;
/** 动态切换实现类 */
public class DubboSPIChangeImplTest {
    public static void main(String[] args) {
        ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
        Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
        System.out.println(optimusPrime.getClass());
        optimusPrime.sayHello();
        Robot bumblebee = extensionLoader.getExtension("bumblebee");
        System.out.println(bumblebee.getClass());
        bumblebee.sayHello();
    }
}

代码运行结果如下图,可以看到通过optimusPrime名字可以拿到对应类的实例。

2.2 支持用户扩展

dubbo框架中的SPI都定义在dubbo.jar的/META-INF/dubbo.internal文件夹下。我们来看一下LoadBalance的SPI。

可以看到LoadBalance SPI已经有5个实现了。我们扩展一个自己的。

1)定义一个LoadBalance实现类AlfLoadBalance

package org.example.test.exExtend;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.LoadBalance;

import java.util.List;
/** 自定义实现类*/
public class AlfLoadBalance implements LoadBalance {
    @Override
    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        return null;
    }
}

2)创建一个配置文件

文件名:org.apache.dubbo.rpc.cluster.LoadBalance

alf=org.example.test.exExtend.AlfLoadBalance

3)编写测试代码

package org.example.test.exExtend;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.cluster.LoadBalance;
/** 动态切换实现类 */
public class DubboSPIExtendTest {
    public static void main(String[] args) {
        ExtensionLoader<LoadBalance> extensionLoader = ExtensionLoader.getExtensionLoader(LoadBalance.class);
        LoadBalance alf = extensionLoader.getExtension("alf");
        System.out.println(alf.getClass().getSimpleName());
        LoadBalance random = extensionLoader.getExtension("random");
        System.out.println(random.getClass().getSimpleName());
    }
}

运行结果:AlfLoadBalance类我们自己定义,RandomLoadBalance类dubbo自带的。

 读到这里,可能有个疑问,dubbo想调用我的实现,如果通过类似LoadBalance alf = extensionLoader.getExtension("alf") 的方法,岂不需要我去修改dubbo源码才能实现?这肯定是不现实的。dubbo通过@Adaptive("loadbalance")自适应SPI+URL参数来解决这个问题的,另起一篇单说吧。

2.3 依赖注入

依赖注入,实现类依赖的属性自动注入,类似spring的依赖注入。

如果字段不想不注入,可以在set方法上使用DisableInject注解。

被依赖注入的属性类的方法必须有@Adaptive注解,即这个类是一个自适应SPI。

本例中OptimusPrime类新添加了属性weapon也是一个扩展。所以该属性会被自动注入到OptimusPrime类的对象中。

例子总体文件图

OptimusPrime类

package org.example.test.exLoader;
/**
 * 擎天柱
 */
public class OptimusPrime implements Robot{
    private Weapon weapon;
    @Override
    public void sayHello() {
        System.out.println("Hello, I am Optimus Prime.");
    }
    public Weapon getWeapon() {
        return weapon;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }
}

Weapon类是接口(dubbo中的扩展),注意@Adaptive("weaponKey")必须有,否则程序会报错。

package org.example.test.exLoader;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI;

@SPI("aWeapon")
public interface Weapon {
    @Adaptive("weaponKey")
    void open(URL url);
}

WeaponA、WeaponB是两个武器的实现类

public class AWeapon implements Weapon{
    @Override
    public void open(URL url) {
        System.out.println("AWeapon");
    }
}
public class BWeapon implements Weapon{
    @Override
    public void open(URL url) {
        System.out.println("BWeapon");
    }
}

org.example.test.exLoader.Weapon 文件

aWeapon = org.example.test.exLoader.AWeapon
bWeapon = org.example.test.exLoader.BWeapon

测试类

package org.example.test.exLoader;
import org.apache.dubbo.common.extension.ExtensionLoader;

/** 动态切换实现类 */
public class DubboSPI_DITest {
    public static void main(String[] args) {
        ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
        Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
        System.out.println(optimusPrime.getClass());
        Weapon weapon = ((OptimusPrime)optimusPrime).getWeapon();
        System.out.println(weapon.getClass());
    }
}

运行结果:Weapon$Adaptive表示是自适应SPI。

依赖注入主要的代码逻辑在ExtensionLoader类的createExtension方法中,感兴趣的同学可以调试以下。

2.4 支持AOP功能

支持类似spring的AOP功能,在dubbo中AOP功能的类要求以Wrapper名字结尾类。

例子总体文件图

Robot是接口,OptimusPrime类是Robot接口的实现类,这两个类上面介绍了,没有修改。Robotwrapper1是一个AOP功能的类,也实现了Robot接口。org.example.test.exLoader.Robot文件是扩展的配置文件。DubboSPI_WrapperTest类是运行类。

 Robotwrapper1类

package org.example.test.exLoader;
/** Robot的wapper */
public class RobotWapper1 implements Robot{
    private Robot robot;
    public RobotWapper1(Robot robot){
        this.robot = robot;
    }
    @Override
    public void sayHello() {
        System.out.println("Before do something!!!");
        this.robot.sayHello();
        System.out.println("After do something!!!");
    }
}

org.example.test.exLoader.Robot文件 

Wrapper前面的名字gaga可以不写,直接写org.example.test.exLoader.RobotWapper1也行。

DubboSPI_WrapperTest类

package org.example.test.exLoader;
import org.apache.dubbo.common.extension.ExtensionLoader;
/** 动态切换实现类 */
public class DubboSPI_WrapperTest {
    public static void main(String[] args) {
        ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
        Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
        optimusPrime.sayHello();
        System.out.println(optimusPrime.getClass().getSimpleName());
    }
}

运行结果:

3 关于配置文件加载路径

请参考LoadingStrategy这个接口的实现类。dubbo会加载3个路径:

ServicesLoadingStrategy类: 加载"META-INF/services/"

DubboLoadingStrategy类: 加载“META-INF/dubbo/”

DubboInternalLoadingStrategy类:加载“META-INF/dubbo/internal/”

4 源码位置

ExtensionLoader类。

5 参考资源

Dubbo SPI | Apache Dubbo

03 Dubbo SPI 精析,接口实现两极反转(上)_哔哩哔哩_bilibili

03 Dubbo SPI 精析,接口实现两极反转(上) - 打工人技术合集

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/131964.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我的2022总结

博客记录 踏石留印 抓铁有痕 使用csdn写博客&#xff0c;发帖子&#xff0c;帮助网友回答问题。都是实实在在满足了学习&#xff0c;交流的需求 这是我自己使用 CSDN 各种功能记录&#xff1a; 工作方面&#xff1a; 年初参与了公司的一个产品&#xff0c;主要负责串口服务…

Allegro上如何计算阻抗操作指导

Allegro上如何计算阻抗操作指导 Allegro上同样可以快捷的进行阻抗计算,免去了用第三方软件计算的麻烦,以下图为例 具体操作如下 选择X-section在层叠中把每个层的Dielectric Constant填写正确,即板材的Er值

01月份图形化二级打卡试题

活动时间 从2023年 1月1日至1月21日&#xff0c;每天一道编程题。 本次打卡的规则如下&#xff1a; &#xff08;1&#xff09;小朋友每天利用10~15分钟做一道编程题&#xff0c;遇到问题就来群内讨论&#xff0c;我来给大家答疑。 &#xff08;2&#xff09;小朋友做完题目后&…

阿里云迎来新主帅,张勇将交出怎样的答卷?

‍‍数据智能产业创新服务媒体——聚焦数智 改变商业岁末年尾&#xff0c;回顾过去展望新篇之际&#xff0c;阿里巴巴集团于29日通过两封邮件宣布了组织架构的调整。以“沉稳内敛”著称的张勇&#xff0c;在解决公司问题时&#xff0c;却尽显雷霆手段。敢于作出不完美的决定在…

【算法】静态单链表、双链表、单调栈与单调队列

文章目录1.单链表2.双链表3.单调栈4.单调队列1.单链表 考虑到效率问题&#xff0c;如果每次都去new结点效率比较慢&#xff0c;平时做题时不采用动态:在有严格的时间要求的环境中&#xff0c;不能频繁使用new操作,new的底层涉及内存分配&#xff0c;调用构造函数&#xff0c;指…

2023创业可以做什么项目,适合新手的六个创业项目推荐

大家好&#xff0c;我是蝶衣王的小编 ​2022年已经进入最后一天了&#xff0c;明天就要步入2023年&#xff0c;个人感觉&#xff0c;明年注定是不平凡的一年&#xff0c;疫情解封&#xff0c;经济生产逐渐恢复&#xff0c;明年开始&#xff0c;创业或者做副业的人肯定会越来越…

视频分割很简单,教你方法三分钟搞定视频剪辑

很多朋友不知道怎么分割视频&#xff0c;今天小编就分享怎么在电脑上分割视频的方法&#xff0c;使用媒体梦工厂操作起来不难&#xff0c;新手小白也能轻松学会&#xff0c;一起接着往下看吧。 第一步&#xff0c;开始剪辑之前&#xff0c;小编准备了多段视频用于演示分割效果&…

【金猿案例展】某大型国有银行——智慧金融产业大脑建设

‍拓尔思案例本项目案例由拓尔思投递并参与“数据猿年度金猿策划活动——《2022大数据产业年度创新服务企业》榜单/奖项”评选。‍数据智能产业创新服务媒体——聚焦数智 改变商业该银行为提高金融领域产业经济分析能力&#xff0c;建设智慧金融产业大脑&#xff0c;通过投融资…

计算机组成原理【1】

目录 考点1&#xff1a;硬件发展———————————————————————————— 一.计算机硬件的基本组成 1.早期冯诺依曼机 &#xff08;1&#xff09;冯.诺依曼计算机的特点: 2.现代计算机的结构 3.总结图 二.各个硬件的工作原理 1.寄存器MAR,MDR 2.主存…

Redis 如何解决内存占用过大、不释放的问题

错误日志 通过 redis.log 可以看到错误日志如下&#xff1a;Cannot allocate memory 15602:M 30 Dec 2022 17:39:09.988 * RDB memory usage when created 19775.56 Mb 15602:M 30 Dec 2022 17:39:44.766 # Done loading RDB, keys loaded: 529954, keys expired: 26. 15602:…

基于长短期记忆网络和凸优化算法的综合智能电网的可再生能源预测(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

string(四)————底层实现

目录 引言 外层包装 成员变量设计 接口实现 引言 在之前的博客中我简单介绍了string的相关使用方法和接口&#xff0c;现在我们自己来模拟实现一下它的底层&#xff08;注&#xff1a;不同编译器底层实现不同&#xff0c;这里只是其中一种的实现&#xff09;。 外层包装 …

Allegro如何在PCB上查看焊盘信息操作指导

Allegro如何在PCB上查看焊盘信息操作指导 在做PCB设计的时候需要查看焊盘的信息,Allegro上支持直接在PCB上查看焊盘的信息,如下图 具体操作如下 选择Tools-Pad stack选择Modify Design Padstack

【漏洞复现】Django SQL注入漏洞 (CVE-2022-28346)

文章目录一、简介二、漏洞概述三、漏洞影响版本四、漏洞分析五、漏洞复现六、修复方法一、简介 Django是用Python开发的一个免费开源的Web结构&#xff0c;几乎包括了Web使用方方面面&#xff0c;能够用于快速建立高性能、文雅的网站&#xff0c;Diango提供了许多网站后台开发…

pcl 姿态变换 之 旋转平移

一、简介 最近在做一个点云的项目&#xff0c;姿态的变换是一个很重要的环节&#xff0c;从数学上需要彻底理解这些东西之前一直在使用&#xff0c;但是没有系统的总结过&#xff0c;接着2023年元旦的三天时间好好学习一下&#xff0c;然后在同事面前说自己是数学系的很丢人啊…

【MySQL进阶】从计算机层面看索引凭什么让查询效率提高这么多?

【MySQL进阶】从计算机层面看索引凭什么让查询效率提高这么多&#xff1f; 文章目录【MySQL进阶】从计算机层面看索引凭什么让查询效率提高这么多&#xff1f;磁盘IO和预读&#xff1a;索引是什么&#xff1f;BTree索引BTree索引让我们先来了解一下计算机的数据加载。磁盘IO和预…

中国为印尼建设的高铁顺利推进,印度网友与日本网友就高铁互怼

日前中国为印尼建设的雅万高铁已开始进行试运行测试&#xff0c;预计将在明年6月正式运行&#xff0c;与雅万高铁差不多时间开始的日本为印度孟买建设的高铁项目才建设了15公里&#xff0c;为此印度网友和日本网友对中日高铁技术的差距展开了争论。2011年日本相关机构开始对印尼…

羊的第四天,开始这篇年终总结

比较尴尬&#xff0c;从今年“羊”到明年&#xff0c;所以这篇文章也是每天抽出一点时间写写&#xff0c;可能会比较乱&#xff0c;先大致分下核心内容吧&#xff1a;今年总结新年展望今年总结先是完成了《数字硬件建模系列的Verilog篇》&#xff0c;效果不好不坏&#xff0c;主…

算法设计与分析复习03:动态规划算法

算法设计与分析复习03&#xff1a;动态规划算法 文章目录算法设计与分析复习03&#xff1a;动态规划算法复习重点动态规划算法斐波那契数列及其应用矩阵链乘法凸多边形剖分矩阵链乘法凸多边形剖分最长公共子序列最大子段和&#xff08;字数组&#xff09;0-1背包编辑距离钢条切…

pycharm-qt5-designer1

pycharm-qt5-designer1一: designer界面介绍1. 新建模板二: 控件箱简介1. Layouts 布局2. Spacers 间隔(透明)3. Button4. Item views5. Item Widgets 条目控件6. Containers 容器7. input Widgets 输入控件8. Display Widgets 显示控件三: 控件属性简介1. sizePolicy: 控件大小…