SPI 机制-插件化扩展功能
2019-08-29 10:00
218 查看
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 的功能,下篇文章可以在具体聊聊,敬请期待。
相关文章推荐
- Java SPI机制实现插件化扩展功能
- Dubbo中SPI扩展机制详解
- Dubbo中SPI扩展机制解析
- 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ Tab功能扩展完结版)
- 理解 Dubbo SPI 扩展机制
- Dubbo中SPI扩展机制解析
- 使用Dubbo的SPI扩展机制实现自定义LoadBalance——方法一 修改Dubbo源代码
- [转] 理解 Dubbo SPI 扩展机制
- Android 5的嵌套滑动机制 和 RecyclerView的一些扩展功能
- Dubbo源码分析 ---- 基于SPI的扩展实现机制
- spring源码深度解析-2功能扩展
- CListCtrl控件功能扩展(滚动条)总结
- 从头认识Spring-3.8 简单的AOP日志实现(注解版)-扩展增加检查订单功能,以便记录并检测输入的参数
- 扩展GridView控件(索引) - 增加多个常用功能(收藏)
- Android--推送机制实现原理(三)-自己实现推送功能--建立长连接
- 扩展系统功能——装饰模式
- Java 动态代理机制分析及扩展,第 2 部分
- 扩展UltraGrid控件实现对所有数据行的全选功能[Source Code下载]
- Eclipse 插件开发 -- 深入理解菜单(Menu)功能及其扩展点
- [Erlang 0101] Gproc:扩展进程注册机制