专栏首页程序通事SPI 机制-插件化扩展功能

SPI 机制-插件化扩展功能

SPI(Service Provider Interfaces),中文直译服务提供者接口,一种服务发现机制。可能很多人都不太熟悉这个机制,但是平常或多或少都用到了这个机制,比如我们使用 JDBC 连接操作数据库的时候。

SPI 主要适用于功能扩展的场景,如一些框架提供某一部分功能可以由第三方开发人员扩展,满足其自身业务需求。

假设我们在公司内实现了一个统一登陆框架,框架内部仅仅提供用户名/密码登陆方式。后来 A 部门想使用该框架,但是他们想增加微信登陆授权。正常情况下,我们可以改动登陆框架代码,增加微信登陆实现方式。如果后面又增加 QQ 登陆,淘宝登陆那?也只能不断相应的实现。

SPI 实现方式

这种情况如果使用 SPI,可以在不用改动框架代码前提下,增加新的登陆实现方式。下面用代码演示如何使用 SPI。

定义接口

首先我们新建一个 maven 项目 oauth-api,在这个项目创建一个公共接口。

public interface OauthLoginService {
    void login();
}

第三方实现该接口

再新建一个 maven 项目 wechat-oauth ,引入上面 oauth-api 依赖

public class WechatLoginService implements OauthLoginService {
    @Override
    public void login() {
        System.out.println("使用微信登陆授权");
    }
}

定义配置文件

SPI 需要将接口实现定义在配置文件中,文件名为接口全名称,如 com.andyxh.OauthLoginService,配置文件需放在 resources\META-INF\services 文件夹下。文件内容如下:

com.another.WechatLoginService

加载接口实现类

新建 maven 项目 oauth-login,在这个项目中引入 wechat-oauthoauth-api 依赖。SPI 核心将会使用 java.util.ServiceLoader读取上面上面定义配置文件,加载所有服务实现类。使用代码如下:

ServiceLoader<OauthLoginService> serviceLoader=ServiceLoader.load(OauthLoginService.class);
serviceLoader.forEach(OauthLoginService::login);

打印结果:

使用微信登陆授权

SPI 实际应用

上面说过 JDBC 中使用到 SPI 进制。 JDK 定义标准数据库接口,相应的数据库厂商实现这类接口。以 mysql-connector-javal 为例。

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

mysql jar 包 META-INF/services 中存在java.sql.Driver 文件,这个文件定义了实现类。

com.mysql.cj.jdbc.Driver

可以看到 java.sql.Driver 是标准 SPI 接口,而 com.mysql.cj.jdbc.Driver 是 mysql 标准实现接口。

何时加载 java.sql.Driver

我们将会使用 DriverManager.getConnection 获取相应数据库连接。这个类内部存在一个静态代码块,将会使用 ServiceLoader 加载实现类。

    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

 private static void loadInitialDrivers() {
        ....
     ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);  
     Iterator<Driver> driversIterator = loadedDrivers.iterator();  
     try{  
         while(driversIterator.hasNext()) {  
         driversIterator.next();  
     }  
     } catch(Throwable t) {  
         // Do nothing  
     }  
         return null;  
     }
    ....
    }

Java SPI 存在问题

ServiceLoader 一次性将会实例化所有实现,但是如果没有某一扩展初始化耗时很久,但是却不需要立刻使用,就会非常浪费资源。

基于这个问题, Dubbo SPI 机制改进 Java SPI 的不足,做到按需加载并且增加 ioc 与 aop 的功能,下篇文章可以在具体聊聊,敬请期待。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 为什么选择 Intellij IDEA 作为日常开发工具

    作为一个从事 Java 开发的程序员,每天离不开编辑器的帮助。还记得刚开始学习 Java 编程的时候,使用 Eclipse 作为日常开发工具。后来工作以后,需要...

    andyxh
  • 还不知道如何使用 IDEA ?教你三招快速掌握 IDEA

    IntelliJ IDEA 是一个非常强大的 IDE,拥有许多功能。在 IDEA 中大部分功能都可以用快捷键去完成,如果掌握了大部分快捷键,可以只使用键盘开发了...

    andyxh
  • 解决 IDEA 无法找到 java.util.Date 的问题

    最近在项目中频繁使用到 java.util.Date,但是使用 IDEA 提示查找 Date 类,却无法找到 java.util.Date。

    andyxh
  • 手把手教你设置 IntelliJ IDEA 的彩色代码主题

    版权声明:Follow your heart and intuition. https://...

    CG国斌
  • 数据分析行业招聘职位分析报告--基于拉勾网

    大数据时代的到来让数据在公司决策上发挥了越来越大的作用,数据分析师也成为了各大企业的标配,那么各大企业又会愿意花多少代价来为数据买单呢?本文将通过从拉勾网爬取到...

    Awesome_Tang
  • 卡方分布与卡方检验

    卡方分布 卡方分布(chi-square distribution, ? -distribution)是概率统计里常用的一种概率分布,也是统计推断里应用最广泛的...

    zenRRan
  • SDN实战团分享(七):YANG模型与OpenDaylight南北向接口

    YANG模型是什么? YANG模型是一种数据建模语言,用来建模由NETCONF协议、NETCONF远端过程调用(RPCs)、和NETCONF通知(notific...

    SDNLAB
  • OpenCV图像噪声与去噪函数方法对比使用介绍

    图像去噪在二值图像分析、OCR识别预处理环节中十分重要,最常见的图像噪声都是因为在图像生成过程中因为模拟或者数字信号受到干扰而产生的,常见的噪声类型有如下:

    OpenCV学堂
  • pdf怎么加密?绝对放心的方法

    PDF主要应用于一些重要的文件,比如发票,账单等重要的文件都需要用PDF展现,那么PDF文件的重要性就不言而喻,那到底pdf怎么加密呢?

    用户5418005
  • 企业数字化转型中的网络安全建设 | FIT 2019议题前瞻「企业安全俱乐部」

    在“互联网+”时代中,企业呈现出互联互通的特性,全球经济数字化转型速率不断提升,针对性的网络攻击的影响比以往任何时候都更加广泛,同时现在有很多的中小型企业进行网...

    FB客服

扫码关注云+社区

领取腾讯云代金券