Java SPI 与 Dubbo SPI

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

在Java中SPI是被用来设计给服务提供商做插件使用的。基于策略模式来实现动态加载的机制。我们在程序只定义一个接口,具体的实现交个不同的服务提供者;在程序启动的时候,读取配置文件,由配置确定要调用哪一个实现。有很多组件的实现,如日志、数据库访问等都是采用这样的方式,最常用的就是 JDBC 驱动。

1.  Java SPI

核心类:java.util.ServiceLoader

服务是一组众所周知的接口和(通常是抽象的)类。服务提供者是服务的特定实现。提供者中的类通常实现接口,并子类化服务本身中定义的类。服务提供者可以以扩展的形式安装在Java平台的实现中,即放置在任何常见扩展目录中的jar文件。提供程序也可以通过将它们添加到应用程序的类路径或其他特定于平台的方法来提供。

通过在资源目录META-INF/services中放置一个提供程序配置文件来识别服务提供程序。文件名是服务类型的完全限定二进制名称。该文件包含具体提供程序类的完全限定二进制名的列表,每行一个。每个名称周围的空格和制表符以及空白行将被忽略。注释字符是'#';在每一行中,第一个注释字符之后的所有字符都将被忽略。文件必须用UTF-8编码。

按照上面的方法,我们来写个例子试一下

首先,定义一个接口Car

package org.example;

public interface Car {
    void run();
}

两个实现类

ToyotaCar.java

package org.example;

public class ToyotaCar implements Car {
    @Override
    public void run() {
        System.out.println("Toyota");
    }
}

HondaCar.java

package org.example;

public class HondaCar implements Car {
    @Override
    public void run() {
        System.out.println("Honda");
    }
}

在META-INF/services下创建一个名为org.example.Car的文本文件

org.example.ToyotaCar
org.example.HondaCar

最后,写个测试类运行看一下效果

package org.example;

import java.util.ServiceLoader;

public class App
{
    public static void main( String[] args )
    {
        ServiceLoader<Car> serviceLoader = ServiceLoader.load(Car.class);
        serviceLoader.forEach(x->x.run());
    }
}

跟一下ServiceLoader的代码,看看是怎么找到服务实现的

用当前线程的类加载器加载

接口和类加载器都有了,万事俱备只欠东风

Java SPI 不足之处:

  • 不能按需加载。Java SPI在加载扩展点的时候,会一次性加载所有可用的扩展点,很多是不需要的,会浪费系统资源
  • 获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类
  • 不支持AOP与IOC
  • 如果扩展点加载失败,会导致调用方报错,导致追踪问题很困难

2.  Dubbo SPI

Dubbo重新实现了一套功能更强的SPI机制, 支持了AOP与依赖注入,并且利用缓存提高加载实现类的性能,同时支持实现类的灵活获取。

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

核心类:org.apache.dubbo.common.extension.ExtensionLoader

先来了解一下@SPI注解,@SPI是用来标记接口是一个可扩展的接口

改造一下前面的例子,在Car接口上加上@SPI注解

package org.example;

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

@SPI
public interface Car {
    void run();
}

两个实现类不变

在META-INF/dubbo目录下创建名为org.example.Car的文本文件,内容如下(键值对形式):

toyota=org.example.ToyotaCar
honda=org.example.HondaCar

编写测试类

package org.example;

import org.apache.dubbo.common.extension.ExtensionLoader;

import java.util.ServiceLoader;

public class App
{
    public static void main( String[] args )
    {
        //  Java SPI
        ServiceLoader<Car> serviceLoader = ServiceLoader.load(Car.class);
        serviceLoader.forEach(x->x.run());

        //  Dubbo SPI
        ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);
        Car car = extensionLoader.getExtension("honda");
        car.run();
    }
}

下面跟一下代码

如果缓存Map中有,直接返回,没有则加载完以后放进去

加载策略到底是怎样的呢?

到这里就有点明白了,又看到了熟悉的ServiceLoad.load(),这不是刚才讲的Java SPI嘛

回到之前策略那个地方,将策略按顺序排列,依次遍历所有的策略来加载。就是在那三个目录下查找指定的文件,并读取其中的内容

跟之前的ServiceLoader如出一辙

遇到@Adaptive标注的就缓存起来

下课

(0)

相关推荐

  • Dubbo常见题目

    前言 我会列举一些常见的 Dubbo 面试题,只会抓着重的,一些太简单的我就不提了. 不仅仅给你面试题的答案,也会剖析面试官问这个问题的原因,也就是他的内心活动. 想从你这里问出什么?想要什么答案?想 ...

  • JDK/Dubbo/Spring 三种 SPI 机制,谁更好?

    空无 写代码的渣渣鹏 昨天 来源:juejin.cn/post/6950266942875779108 SPI 全称为 Service Provider Interface,是一种服务发现机制.SPI ...

  • Java SPI机制详解

    SPI介绍 SPI ,全称为 Service Provider Interface,是一种服务发现机制,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件. SPI的 ...

  • Dubbo的SPI自适应扩展

    最近看Dubbo源码的时候,最开始对Dubbo的自适应扩展一直没怎么看明白,参考其他的博客大多也就是把官方的代码解释搬过来,然并卵. 对SPI不明白可以参考官方文档 最后按照自己的理解来模拟了一下,希 ...

  • SPI通信协议(SPI总线)学习

    SPI通信协议(SPI总线)学习

  • 高级开发必须理解的Java中SPI机制

    本文通过探析JDK提供的,在开源项目中比较常用的Java SPI机制,希望给大家在实际开发实践.学习开源项目提供参考. 1 SPI是什么 SPI全称Service Provider Interface ...

  • Soul的SPI以及负载均衡策略研究

    Soul的SPI以及负载均衡策略研究 上一节留下的几个问题在之后进行的研究 如何从abstractSoulPlugin执行完之后到WebClientPlugin的相同方法,是责任链模式还是其他的加载过 ...

  • 赛普拉斯代理4Mbit串行SPI铁电存储器CY15B104Q-LHXI

    赛普拉斯型号CY15B104Q-LHXI主要采用先进铁电工艺的4Mbit非易失性存储器.铁电随机存取存储器或FRAM是非易失性的,并且执行类似于RAM的读取和写入操作.它提供了151年的可靠数据保留, ...

  • Xilinx FPGA 从spi flash启动配置数据时的地址问题

    FPGA上电(Master) fpga 上电时,默认是从 flash 的 0x00 地址开始读数据.如 UG470 文档 page144 描述 fpga 会从 0 开始读,地址不断自增,直到读取到有效 ...

  • iMX8MQ如何在SPI总线上添加设备-飞凌嵌入式干货分享

    SPI接口设备是一款使用率较高的设备,在用户使用OKMX8MQ-C时可能需要添加新的SPI设备,或者将现有的SPI设备从当前的总线上更换到别的总线上,或更换片选. 对于SPI驱动不熟悉的人可能不是很了 ...