文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JDK与Dubbo中的SPI详细介绍

2024-04-02 19:55

关注

1、SPI简介

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。 目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现的机制。使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。

2、JDK中的SPI

Java中如果想要使用SPI功能,先提供标准服务接口,然后再提供相关接口实现和调用者。这样就可以通过SPI机制中约定好的信息进行查询相应的接口实现。

SPI遵循如下约定:

入门案例

模块结构如下

(1)api模块

此模块创建了一个接口,供后续模块使用

package com.lagou.service;
public interface HelloService {
    String sayHello();
}

(2)impl模块

此模块中提供了api模块接口的实现类,并且在resource目录下,创建了配置文件。

实现类

package com.lagou.service.impl;
import com.lagou.service.HelloService;
public class HumanHelloService implements HelloService {
    @Override
    public String sayHello() {
        return "hello world";
    }
}

配置文件(名称为接口全限定名, 内容为接口实现类全限定类名)

com.lagou.service.impl.HumanHelloService

(3)main模块

提供了测试jdk-spi的的类

package com.lagou.test;
import com.lagou.service.HelloService;
import java.util.ServiceLoader;
public class JavaSpiMain {
    public static void main(String[] args) {
        final ServiceLoader<HelloService> helloServices = ServiceLoader.load(HelloService.class);
        for (HelloService helloService : helloServices) {
            System.out.println(helloServices.getClass().getName() + ";" + helloService.sayHello());
        }
    }
}

3、Dubbo中的SPI

dubbo中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。比如比较常见的协议,负载均衡,都可以通过SPI的方式进行定制化,自己扩展。Dubbo中已经存在的所有已经实现好的扩展点。

下图中则是Dubbo中默认提供的负载均衡策略。

4、Dubbo中扩展点使用方式

我们使用三个项目来演示Dubbo中扩展点的使用方式,一个主项目main,一个服务接口项目api,一个服务实现项目impl。

(1)api模块

往pom.xml中导入dubbo依赖

       <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.5</version>
        </dependency>

创建接口,并在接口上添加上@SPI注解

package com.lagou.service;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface HelloService {
    String sayHello();
}

(2)impl模块

导入 api项目 的依赖

建立实现类

package com.lagou.service;
public class HumanHelloService implements HelloService{
    @Override
    public String sayHello() {
        return "hello 你好";
    }
}

SPI进行声明操作,在resources 目录下创建目录META-INF/dubbo 目录,在目录下创建名称为接口的全限定类名的文件,文件内部配置实现类名称和对应的全限定名:

human=com.lagou.service.HumanHelloService

(3)main模块

导入坐标、接口项目和实现类项目

创建DubboSpiMain

和原先调用的方式不太相同, dubbo 有对其进行自我重新实现 需要借助ExtensionLoader,创建新的运行项目。这里demo中的示例和java中的功能相同,查询出所有的已知实现,并且调用

package com.lagou;
import com.lagou.service.HelloService;
import org.apache.dubbo.common.extension.ExtensionLoader;
import java.util.Set;
public class DubboSpiMain {
    public static void main(String[] args) {
        // 获取扩展加载器
        ExtensionLoader<HelloService> extensionLoader = ExtensionLoader.getExtensionLoader(HelloService.class);
        // 遍历所有支持的扩展点   META-INF.dubbo
        Set<String> extensions = extensionLoader.getSupportedExtensions();
        for (String extension : extensions) {
            String result = extensionLoader.getExtension(extension).sayHello();
            System.out.println(result);
        }
    }
}

(4)dubbo自己做SPI的目的

1. JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源

2. 如果有扩展点加载失败,则所有扩展点无法使用

3. 提供了对扩展点包装的功能(Adaptive),并且还支持通过set的方式对其他的扩展点进行注入

5、DubboSPI中的Adaptive功能

Dubbo中的Adaptive功能,主要解决的问题是如何动态的选择具体的扩展点。通过getAdaptiveExtension 统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行动态选择。 (dubbo中所有的注册信息都是通过URL的形式进行处理的。)这里同样采用相同的方式进行实现。

(1)创建接口

api中的HelloService 扩展如下方法, 与原先类似,在sayHello中增加Adaptive 注解,并且在参数中提供URL参数.注意这里的URL参数的类为org.apache.dubbo.common.URL,其中@SP可以指定一个字符串参数,用于指明该SPI的默认实现。

package com.lagou.service;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI;
@SPI("human") // 这个human对应配置文件中的human
public interface HelloService {
    String sayHello();
    @Adaptive
    String sayHello(URL url);
}

(2)创建实现类

与上面Service实现类代码相似,只需增加URL形参即可

package com.lagou.service;
import org.apache.dubbo.common.URL;
public class HumanHelloService implements HelloService{
    @Override
    public String sayHello() {
        return "hello 你好";
    }
    @Override
    public String sayHello(URL url) {
        return "hello url";
    }
}

(3)编写DubboAdaptiveMain

最后在获取的时候方式有所改变,需要传入URL参数,并且在参数中指定具体的实现类参数

package com.lagou;
import com.lagou.service.HelloService;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class DubboAdaptiveMain {
    public static void main(String[] args) {
        URL url = URL.valueOf("test://localhost?hello.service=human");
        HelloService adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
        String hello = adaptiveExtension.sayHello(url);
        System.out.println(hello);
    }
}

注意:

到此这篇关于JDK与Dubbo中的SPI详细介绍的文章就介绍到这了,更多相关JDK与Dubbo的SPI内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯