作者:sigangjun

blog.csdn.net/sigangjun/article/details/79071850

SPI的全名为:Service Provider Interface,大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。

简单的总结下 Java  SPI 机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。

一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。

Java  SPI 就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

Java  SPI 的具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。

而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader。


1.common-logging   

apache最早提供的日志的门面接口。只有接口,没有实现。具体方案由各提供商实现, 发现日志提供商是通过扫描 META-INF/services/org.apache.commons.logging.LogFactory配置文件,通过读取该文件的内容找到日志提工商实现类。

只要我们的日志实现里包含了这个文件,并在文件里制定
LogFactory工厂接口的实现类即可。关注Java技术栈微信公众号,在后台回复关键字:Java,可以获取更多栈长整理的Java技术干货。

2.jdbc   

jdbc4.0以前, 开发人员还需要基于Class.forName("xxx")的方式来装载驱动,jdbc4也基于spi的机制来发现驱动提供商了,可以通过META-INF/services/java.sql.Driver文件里指定实现类的方式来暴露驱动提供者。

一个内容管理系统有一个搜索模块。是基于接口编程的。搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索

接口定义如下:



package my.xyz.spi; import java.util.List; public interface Search {    public List serch(String keyword); }
import java.util.List;
public interface Search {
  public List serch(String keyword);
}

A公司采用文件系统搜索的方式实现了 Search接口,B公司采用了数据库系统的方式实现了Search接口。

  • A公司实现的类:com.A.spi.impl.FileSearch

  • B公司实现的类:com.B.spi.impl.DatabaseSearch

那么A公司发布 实现jar包时,则要在jar包中META-INF/services/my.xyz.spi.Search文件中写下如下内容:


com.A.spi.impl.FileSearch.A.spi.impl.FileSearch

那么B公司发布 实现jar包时,则要在jar包中META-INF/services/my.xyz.spi.Search文件中写下如下内容:


com.B.spi.impl.DatabaseSearch.B.spi.impl.DatabaseSearch

下面是 SPI 测试代码:



package com.xyz.factory; import java.util.Iterator; import java.util.ServiceLoader; import my.xyz.spi.Search; public class SearchFactory {    private SearchFactory() {   }    public static Search newSearch() {     Search search = null;     ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class);     Iterator<Search> searchs = serviceLoader.iterator();      if (searchs.hasNext()) {       search = searchs.next();     }     return search;   } }
import java.util.Iterator;
import java.util.ServiceLoader;
import my.xyz.spi.Search;
public class SearchFactory {
  private SearchFactory() {
  }
  public static Search newSearch() {
    Search search = null;
    ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class);
    Iterator<Search> searchs = serviceLoader.iterator();
    if (searchs.hasNext()) {
      search = searchs.next();
    }
    return search;
  }
}

关注Java技术栈微信公众号,在后台回复关键字:Java,可以获取更多栈长整理的Java技术干货。

最近干货分享

Spring Cloud Gateway VS Zuul 怎么选择?

46张PPT弄懂JVM、GC算法和性能调优!

数据库怎么分库分表,垂直?水平?

Zookeeper怎么实现分布式锁?

分享一份Java架构师学习资料

一个人学习、工作很迷茫?

点击「阅读原文」加入栈长的小圈子!

Java 中的 SPI 机制是什么鬼?高级 Java 必须掌握!的更多相关文章

  1. 【Java】深入理解Java中的spi机制

    深入理解Java中的spi机制 SPI全名为Service Provider Interface是JDK内置的一种服务提供发现机制,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用 ...

  2. 结合实战和源码来聊聊Java中的SPI机制?

    写在前面 SPI机制能够非常方便的为某个接口动态指定其实现类,在某种程度上,这也是某些框架具有高度可扩展性的基础.今天,我们就从源码级别深入探讨下Java中的SPI机制. 注:文章已收录到:https ...

  3. java中的SPI机制

    1 SPI机制简介 SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的.在java.util.ServiceLoader的文档里 ...

  4. java中的spi

    JAVA中的SPI机制 1.SPI简介 SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework),是一种将服务接 ...

  5. 一文搞懂Java/Spring/Dubbo框架中的SPI机制

    几天前和一位前辈聊起了Spring技术,大佬突然说了SPI,作为一个熟练使用Spring的民工,心中一紧,咱也不敢说不懂,而是在聊完之后赶紧打开了浏览器,开始的学习之路,所以也就有了这篇文章.废话不多 ...

  6. Java中的SPI原理浅谈

    在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的"开闭原则& ...

  7. java中的反射机制在Android开发中的用处

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...

  8. java中wait/notify机制

    通常,多线程之间需要协调工作.例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程 downloadThread将该图片下载完毕.如果图片还没有下载完,d ...

  9. 浅说Java中的反射机制(二)

    写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...

随机推荐

  1. 记Selenium HTMLTestRunner 无法生成测试报告的总结

      使用Python ,HTMLTestRunner 生成测试报告时,遇到很奇怪的问题,明明运行的结果,没有任何报错,就是不生成测试报告,纠结好久.google+baidu搜索结果也不满意,最后终于解 ...

  2. Address already in use: JVM_Bind 8083端口被占用的几个解决办法

    运行Tomcat时若出现Address already in use: JVM_Bind 端口被占用,一般使用下面几个办法可以解决: 假设端口为8083 1.启动cmd, 执行命令netstat -a ...

  3. Django框架(八)—— 模板层:模板导入、模板继承、静态文件

    目录 模板导入.继承.静态文件 一.模板导入 1.语法 2.使用 二.模板的继承 1.使用模板的继承 2.强调(注意点) 三.静态文件 1.在配置文件settings中配置过静态文件 2.导入使用静态 ...

  4. Java jar文件

    JAR(Java Archive)是基于ZIP文件格式的文件格式. 它用于捆绑Java应用程序或小程序的资源,类文件,声音文件,图像等. 它还提供数据压缩.一个JAR文件作为一种特殊类型的ZIP文件. ...

  5. hibernate 中createQuery与createSQLQuery两者区别

    hibernate 中createQuery与createSQLQuery两者区别是:前者用的hql语句进行查询,后者可以用sql语句查询前者以hibernate生成的Bean为对象装入list返回, ...

  6. NIO 源码分析(03) 从 BIO 到 NIO

    目录 一.NIO 三大组件 Channels.Buffers.Selectors 1.1 Channel 和 Buffer 1.2 Selector 1.3 Linux IO 和 NIO 编程的区别 ...

  7. print的简单使用

    import time num=20 for i in range(num): print("#", end="") 结果如下: 加个强制刷新 num=20 f ...

  8. man bash

    BASH(1) General Commands Manual BASH(1) NAME bash - GNU Bourne-Again SHell SYNOPSIS bash [options] [ ...

  9. python中 try、except、finally执行顺序

    我们虽然经常用到try...except 作为异常补货,但是其实很少去研究try源码和机制,也许点进去看过,也是看不出个所以然来 class Exception(BaseException): &qu ...

  10. C语言typedef

    #include <stdio.h> //基本类型 typedef int MyInt; //可以对typedef产生的类型名二次起别名 typedef MyInt MyInt2; // ...