Java SPI机制简介

SPI是Service Provider Interfaces的简称。根据Java的SPI规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即Service Provider(服务提供者)。然后在使用的时候只要根据SPI的规范去获取对应的服务提供者的服务实现即可。为了便于理解,我们先来看一个使用SPI的示例。

假设我们有一个日志服务LogService,其只定义了一个info方法用于输出日志信息,我们希望把它作为SPI,然后具体的实现由对应的服务提供者去实现。LogService的定义如下所示。

package com.elim.learn.basic.spi.service;

public interface LogService {

public void info(String msg);

}

然后基于这个服务我们会有自己的实现,示例中笔者用了三个实现,分别是ConsoleLogService、FileLogService和DBLogService,其实现都只是简单的打印一下日志类别信息,ConsoleLogService的实现如下所示,其它两个是类似的。

package com.elim.learn.basic.spi.service.impl;

import com.elim.learn.basic.spi.service.LogService;

public class ConsoleLogService implements LogService {

@Override

public void info(String msg) {

System.out.println("----console log ----");

}

}

根据SPI的规范我们的服务实现类必须有一个无参构造方法。我们的SPI服务提供者需要将其在classpath下的META-INF/services目录下以服务接口全路径名命名的文件中写对应的实现类的全路径名称,每一行代表一个实现,如果需要注释信息可以使用“#”进行注释,根据官方的要求,这个文件的编码格式必须是UTF-8。我们示例中的LogService的全路径名是com.elim.learn.basic.spi.service.LogService,所以我们需要在类路径下的META-INF/services目录下创建一个名称为com.elim.learn.basic.spi.service.LogService文件。在本示例中我们一个提供了三个实现,所以该文件的内容如下。

#console

com.elim.learn.basic.spi.service.impl.ConsoleLogService

#file

com.elim.learn.basic.spi.service.impl.FileLogService

#db

com.elim.learn.basic.spi.service.impl.DBLogService

至此,我们的服务定义和实现配置就完成了,接下来就是使用了。使用的时候核心是ServiceLoader类,我们需要通过这个工具类来加载服务提供者,即对应的服务实现,也需要通过它来获得对应的服务实现。ServiceLoader类的核心入口是其提供的三个可以创建ServiceLoader实例的静态方法,分别是load(Class<?> , ClassLoader)、load(Class<?>)和loadInstalled(Class<?>),三者的区别就在于使用的ClassLoader不一样。load(Class<?>)方法将使用当前线程持有的ClassLoader,loadInstalled(Class<?>)方法将使用最顶级的ClassLoader。三者的实现分别如下。

public static <S> ServiceLoader<S> load(Class<S> service,

ClassLoader loader)

{

return new ServiceLoader<>(service, loader);

}

public static <S> ServiceLoader<S> load(Class<S> service) {

ClassLoader cl = Thread.currentThread().getContextClassLoader();

return ServiceLoader.load(service, cl);

}

public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {

ClassLoader cl = ClassLoader.getSystemClassLoader();

ClassLoader prev = null;

while (cl != null) {

prev = cl;

cl = cl.getParent();

}

return ServiceLoader.load(service, prev);

}

ServiceLoader是实现了java.util.Iterator接口的,而且是基于我们所使用的服务的实现,所以可以通过ServiceLoader的实例来遍历其中的服务实现者,从而调用对应的服务提供者。示例如下。

@Test

public void test() {

ServiceLoader<LogService> serviceLoader = ServiceLoader.load(LogService.class);

LogService logService = null;

for (Iterator<LogService> iter = serviceLoader.iterator(); iter.hasNext(); ) {

logService = iter.next();

logService.info("Hello SPI");

}

//由于ServiceLoader是实现了java.util.Iterator接口的,也可以使用增强的for循环

for (LogService service : serviceLoader ) {

service.info("Hello SPI");

}

}

调用结果如下:

在上述示例中我们的基于SPI规范的服务定义和服务实现都是在一个工程里面的,且都是可以看到源码的,但在实际应用中我们的服务提供者往往是以jar包的形式来提供对应的服务实现的。ServiceLoader不是一实例化以后立马就去读配置文件中的服务实现者,并且进行对应的实例化工作的,而是会等到需要通过其Iterator实现获取对应的服务提供者时才会加载对应的配置文件进行解析,具体来说是在调用Iterator的hasNext方法时会去加载配置文件进行解析,在调用next方法时会将对应的服务提供者进行实例化并进行缓存。所有的配置文件只加载一次,服务提供者也只实例化一次,如需要重新加载配置文件可调用ServiceLoader的reload方法。有兴趣的朋友可以参考一下ServiceLoader的完整源码实现。

Java SPI机制简介相关推荐

  1. Flink从入门到精通100篇(十一)-Java SPI 机制在 Flink SQL 中的应用

    Java SPI 机制简介 Java SPI机制,即Java Service Provider Interface,是Java提供的基于"接口编程 + 策略模式 + 配置文件"组合 ...

  2. Java SPI机制详解

    Java SPI机制详解 1.什么是SPI? 2.SPI的用途 Driver实现 Mysql DriverManager实现 spi工具类`ServiceLoader` 将自己注册到驱动管理器的驱动列 ...

  3. Java SPI机制实现插件化扩展功能

    Java SPI机制实现插件化扩展功能 1.背景 我们有一个图数据库的服务,用户希望在不修改现有源代码的情况下扩展自定义的分词器,达到可插件式扩展功能的目标. 通过Java的SPI机制实现插件式的扩展 ...

  4. 深入理解java SPI机制

    What? SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework,参考[EffectiveJava]page6 ...

  5. JAVA SPI机制及SPI机制在Tomcat中的应用

    SPI 是 JAVA 提供的一种服务提供发现接口,其实就是一种面向接口的编程,为接口去匹配具体服务实现的机制,这一点上与 IOC 的思想类似,都是把装配的控制权放到了程序之外,下面具体看看什么是 SP ...

  6. java spi机制_Java是如何实现自己的SPI机制的? JDK源码(一)

    注:该源码分析对应JDK版本为1.8 1 引言 这是[源码笔记]的JDK源码解读的第一篇文章,本篇我们来探究Java的SPI机制的相关源码. 2 什么是SPI机制 那么,什么是SPI机制呢? SPI是 ...

  7. java spi技术,Java SPI机制

    Java组件一个更为人熟知的名词"服务",与流行的微服务有所区别. 以往加载JDBC驱动使用如下方式:Class.forName() Java 1.6引入SPI机制,使用Drive ...

  8. java spi机制_Java 双亲委派机制的破坏—SPI机制

    作者:程序猿微录 出自:TinyRecord 原文:tinyice.cn/articles/123 Java 双亲委派机制的破坏-SPI机制 在Java的类加载机制中,默认的就是双亲委派机制,这种委派 ...

  9. JAVA SPI机制概述

    SPI概述 1.SPI概念 ①全称:Service Provider Interface ②是什么:是Java提供的一套用来被第三方实现或者扩展的接口,从JDBC4.0,JDK6开始Java实现了SP ...

  10. Java SPI机制分析

    2019独角兽企业重金招聘Python工程师标准>>> SPI概述 SPI全称为(Service Provider Interface) ,是JDK内置的一种服务提供发现机制:主要被 ...

最新文章

  1. 小工匠聊架构-Redis 缓存一致性设计
  2. android 消除标题,Android Activity 去掉标题栏及全屏显示
  3. Visual Studio Code现已支持Linux“快照包”安装
  4. Matlab移植到Eigen用到的词条
  5. 用ViewPager实现轮播效果
  6. java中反复使用代码_Java代码复用规则
  7. php如何实现记录步数,微信步数获取-PHP后端部分
  8. 工作流Activiti 6.x
  9. 毕向东java笔记ppt,毕向东java学习笔记.doc
  10. Android下载文件,如何获取实际的文件名
  11. win10“无法完成操作,因为文件包含病毒或潜在的垃圾软件”解决办法
  12. 1、Android APP开发基础
  13. 在Android中加入GOOGLE统计系统
  14. linux cp并打包目录,【linux】【qt5】【将linux下的qt程序打包发布(完全适用于中标麒麟)】...
  15. 数据保护与云不离不弃,云中护航渐成行业主旋律
  16. linux cadaver 命令,(个人学习Linux经历)文本命令
  17. 群、环、域基础与例子
  18. linux下制作linux系统的安装U盘
  19. Realtek PCIe GBE Family Controller(有线网卡)及Intel(R) Wi-Fi 6 AX201 160MHz(无线网卡)前出现出现黄色感叹号!解决方法。(win10)
  20. 英语口语练习十七之I can't figure out... (我搞不懂……)的用法

热门文章

  1. Python中的unittest模块(入门学习款)
  2. stm32for循环几个机械周期_带你了解包装机械设备的可调度性分析
  3. 姚聪 旷世_首款国产豪华品牌大型SUV,汉龙旷世品质气场100分! - 快讯
  4. 计算机名ip自动配置文件,[已解决]批处理如何根据网卡MAC地址自动设置IP和计算机名?...
  5. mysql 存储过程 注入_MySQL数据库(六)-- SQL注入攻击、视图、事物、存储过程、流程控制...
  6. python-docx下载_python-docx
  7. tomcat 8安装 linux,linux下tomcat8安装详解(附图解步骤)
  8. python qt刷新_Python Qt.SizeFDiagCursor方法代码示例
  9. ifconfig知识总结
  10. 完成的定义 Definition of Done