码迷,mamicode.com
首页 > 其他好文 > 详细

【Dubbo】04. Dubbo中的SPI

时间:2021-04-22 16:21:43      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:ade   文件   代码   ons   extension   provider   nts   meta   sources   

04. Dubbo中的SPI

1. SPI简介

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

2. JDK中的SPI

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

2.1 SPI遵循如下约定:

  • 当服务提供者提供了接口的一种具体实现后,在META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
  • 接口实现类所在的jar包放在主程序的classpath中;
  • 主程序通过java.util.ServiceLoader动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
  • SPI的实现类必须携带一个无参构造方法;

2.2 示例:

2.2.1 新建空白maven项目

创建空白项目——java_spi_demo

2.2.2 新建module,并定义接口

创建module——java_spi_demo_api
新建

package com.dxh.service;

public interface HelloService {
    String sayHello();
}

2.2.3 新建服务提供者module,编写实现类

创建module——java_spi_demo_impl
pom中加入依赖

<dependency>
    <groupId>com.dxh</groupId>
    <artifactId>java_spi_demo_api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

编写实现类

package com.dxh.service.impl;
import com.dxh.service.HelloService;

public class HumanHelloService implements HelloService {
    @Override
    public String sayHello() {
        return "Hello 你好~";
    }
}

在resource下建立文件夹——META-INF.services
在META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名
新建文件com.dxh.service.HelloService

com.dxh.service.impl.HumanHelloService

2.2.4 新建主程序module,编写测试方法

新建module——java_spi_demo_main
新建测试方法

package com.dxh.test;

import com.dxh.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(helloService.getClass().getName()+":"+helloService.sayHello());
        }
    }
}

2.2.5 运行测试

返回结果:com.dxh.service.impl.HumanHelloService:Hello 你好~

目录结构:
技术图片

3. Dubbo中的SPI

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

下图中则是Dubbo中默认提供的负载均衡策略:
技术图片

3.1 Dubbo扩展点的使用

分为三个项目演示:

  • 服务接口项目api
  • 服务实现项目impl
  • 主项目main

新建maven项目:dubbo_spi_demo

3.1.1 服务接口项目

  1. 新建module-dubbo_spi_demo_api
  2. pom中增加依赖,用于定义接口时使用@SPI注解
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.5</version>
</dependency>
  1. 新建接口
package com.dxh.service;
import org.apache.dubbo.common.extension.SPI;

@SPI
public interface HelloService {
    String sayHello();
}

3.1.2 服务端实现项目

  1. 新建module-dubbo_spi_demo_impl
  2. pom中增加依赖
<dependency>
    <groupId>com.dxh</groupId>
    <artifactId>dubbo_spi_demo_api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  1. 新建接口实现类
package com.dxh.service.impl;
import com.dxh.service.HelloService;

public class HumanServiceImpl implements HelloService {
    @Override
    public String sayHello() {
        return "Hello 你好";
    }
}
  1. 在resources中新建文件夹META-INF/dubbo,区别于JDK提供的spi的文件名META-INF/services
  2. 在文件夹中新建文件,目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名
human=com.dxh.service.impl.HumanServiceImpl

3.1.3 主程序项目

  1. 新建module-dubbo_spi_demo_main
  2. pom中增加依赖
<dependency>
    <groupId>com.dxh</groupId>
    <artifactId>dubbo_spi_demo_api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>com.dxh</groupId>
    <artifactId>dubbo_spi_demo_impl</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  1. 新建入口类
    和JDK SPI不同,dubbo对其进行自我重新实现,需要借助ExtensionLoader。
package com.dxh;
import com.dxh.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 sayHello = extensionLoader.getExtension(extension).sayHello();
            System.out.println(sayHello);
        }
    }
}
  1. 运行测试:Hello 你好

目录结构:
技术图片

4. Dubbo自己做SPI的目的

  1. JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源
  2. 如果有扩展点加载失败,则所有扩展点无法使用
  3. 提供了对扩展点包装的功能(Adaptive),并且还支持通过set的方式对其他的扩展点进行注入

【Dubbo】04. Dubbo中的SPI

标签:ade   文件   代码   ons   extension   provider   nts   meta   sources   

原文地址:https://www.cnblogs.com/isdxh/p/14687645.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!