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-oauth 与 oauth-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 的功能,下篇文章可以在具体聊聊,敬请期待。

SPI 机制-插件化扩展功能的更多相关文章

  1. ASP.NET MVC 插件化机制

    概述 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具 体实 ...

  2. ASP.NET MVC5 插件化机制简单实现

    一.前言 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具体 ...

  3. 小白也能看懂的插件化DroidPlugin原理(二)-- 反射机制和Hook入门

    前言:在上一篇博文<小白也能看懂的插件化DroidPlugin原理(一)-- 动态代理>中详细介绍了 DroidPlugin 原理中涉及到的动态代理模式,看完上篇博文后你就会发现原来动态代 ...

  4. 在.NET Core中使用简单的插件化机制

    前言 插件化,其实也并不是什么新东西了,像nopCommerce等开源项目都有类似的机制,而且功能比较完善和齐全. 相信大家都对接过不少支付方式,支付宝.微信以及各大银行或第三方的支付公司. 我们可以 ...

  5. ASP.NET:插件化机制

    概述 nopCommerce的插件机制的核心是使用BuildManager.AddReferencedAssembly将使用Assembly.Load加载的插件程序集添加到应用程序域的引用中.具体实现 ...

  6. Android插件化原理解析——Hook机制之动态代理

    转自 http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/ 使用代理机制进行API Hook进而达到方法增强是框架的常 ...

  7. 组件化框架设计之Java SPI机制(三)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 本篇文章将从深入理解java SPI机制来介绍组件化框架设计: ...

  8. Java SPI机制:ServiceLoader实现原理及应用剖析

    一.背景 SPI,全称Service Provider Interfaces,服务提供接口.是Java提供的一套供第三方实现或扩展使用的技术体系.主要通过解耦服务具体实现以及服务使用,使得程序的可扩展 ...

  9. Apache DolphinScheduler 2.0.1 来了,备受期待的一键升级、插件化终于实现

    ✎ 编 者 按:好消息!Apache DolphinScheduler 2.0.1 版本正式发布! 本版本中,DolphinScheduler 经历了一场微内核+插件化的架构改进,70% 的代码被重构 ...

随机推荐

  1. Git学习(一):版本控制介绍及安装

    一.VCS(版本控制系统)的演变 1.集中式VCS的特点 1)有集中的版本管理服务器: 2)具备文件版本管理和分支管理能力: 3)集成效率较没有版本控制(如:进行文件夹标注的方式)有明显地的提高: 4 ...

  2. NetworkStream.Read

    Reads data from the NetworkStream. 参数 buffer 类型:System.Byte[]类型 Byte 的数组,它是内存中用于存储从 NetworkStream 读取 ...

  3. 小白学python-day01-电脑结构知识

    作为一个”0“基础的经济学学士来说,专业分类选择了经统,多多少少和计算机有点关系,从今天开始学习python. 但行努力,莫问前程. day01学习电脑结构等知识. 因为这些知识是 有规则的,客观的文 ...

  4. php 排序和置顶功能实现

    (1)排序操作思路 一般来说都是按照发布时间排序.时间戳大的靠前,所以用倒序desc,而不是asc (2)置顶操作思路: 点击置顶时,修改数据库addtime字段值为当前时间即可.因为排序是按照时间戳 ...

  5. JavaScript常用语句

    JavaScript常用语句 语句 语法 说明 简单语句 : 语句以:分号结束 语句块 {} 将一组语句组成语句块,ES中没有语句块作用域,也可用作对象字面量 添加标签语句 label 给代码添加标签 ...

  6. C#汽车租赁系统 完整版

      Truck.cs类 //卡车类 public class Truck : Vehicle1 { //重载 public int Load { get; set; } //构造函数 public T ...

  7. Git 学习笔记之(一) 使用 git gui 从github上下载代码

    背景: 目前一些开源代码均在 GitHub上管理的,包括自己写的代码也可以放在上面进行管理.但问题是,当你换一台电脑,想要将你自己放在 GitHub 上的代码工程下载下来的时候,会遇到各种问题,目前可 ...

  8. setInterval循环设置并传入不同的参数

    var taskId; var __sto = setInterval; window.setInterval = function(callback,timeout,param){ var args ...

  9. Scala集合(四)

    1. 集合 集合主要有三种: Sequence Map Set sequence是一种线性元素的集合,可能会是索引或者线性的(链表).map是包含键值对的集合,就像Java的Map,set是包含无重复 ...

  10. [转] java开源游戏

    收藏一下   triplea  Triplea是一个开放源码的boardgame.它允许玩家选择各种各样的战略版图游戏(如:轴心国或同盟军).TripleA引擎支持联网对战,支持声音,支持使用XML文 ...