深入学习Java中的SPI机制

概述

SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。

Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦。

SPI整体机制图如下

当服务的提供者提供了一种接口的实现之后,需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。JDK中查找服务的实现的工具类是:java.util.ServiceLoader。

java.util.ServiceLoader

首先,ServiceLoader实现了Iterable接口,所以它有迭代器的属性,这里主要都是实现了迭代器的hasNext和next方法。这里主要都是调用的lookupIterator的相应hasNext和next方法,lookupIterator是懒加载迭代器。

其次,LazyIterator中的hasNext方法,静态变量PREFIX就是”META-INF/services/”目录,这也就是为什么需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件。

最后,通过反射方法Class.forName()加载类对象,并用newInstance方法将类实例化,并把实例化后的类缓存到providers对象中,(LinkedHashMap<String,S>类型) 然后返回实例对象。

demo

//定义一个接口HelloSPI。
package com.vivo.study.spidemo.spi;
public interface HelloSPI {
  void sayHello();
}
//完成接口的多个实现。
package com.vivo.study.spidemo.spi.impl;
import com.vivo.study.spidemo.spi.HelloSPI;
public class ImageHello implements HelloSPI {
  public void sayHello() {
    System.out.println("Image Hello");
  }
}
package com.vivo.study.spidemo.spi.impl;
import com.vivo.study.spidemo.spi.HelloSPI;
public class TextHello implements HelloSPI {
  public void sayHello() {
    System.out.println("Text Hello");
  }
}
//在META-INF/services/目录里创建一个以com.vivo.study.spidemo.spi.HelloSPI的文件,这个文件里的内容就是这个接口的具体的实现类。
内容如下
com.vivo.study.spidemo.spi.impl.ImageHello
com.vivo.study.spidemo.spi.impl.TextHello
// 使用 ServiceLoader 来加载配置文件中指定的实现
package com.vivo.study.spidemo.test
import java.util.ServiceLoader;
import com.vivo.study.spidemo.spi.HelloSPI;
public class SPIDemo {
  public static void main(String[] args) {
    ServiceLoader<HelloSPI> serviceLoader = ServiceLoader.load(HelloSPI.class);
    // 执行不同厂商的业务实现,具体根据业务需求配置
    for (HelloSPI helloSPI : serviceLoader) {
      helloSPI.sayHello();
    }
  }
}
//输出结果如下:
Image Hello
Text Hello

不足

1.不能按需加载,需要遍历所有的实现,并实例化,然后在循环中才能找到我们需要的实现。如果不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。

2.获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类。

3.多个并发多线程使用 ServiceLoader 类的实例是不安全的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解java 三种调用机制(同步、回调、异步)

    1:同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用 2:回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口: 3:异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口 具体说来:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法, 实例1:使用java中Timer来在给定时间间隔发送通知,每隔十秒打印一次数据 Tim

  • java获取反射机制的3种方法总结

    反射机制的概念: 指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制. 反射机制的应用: 生成动态代理,面向切片编程(在调用方法的前后各加栈帧). 反射机制的原理: 1 首先明确的概念: 一切皆对象----类也是对象. 2 然后知道类中的内容 :modifier constructor field method. 3 其次明白加载: 当Animal.class在硬盘中时

  • Java编程Retry重试机制实例详解

    本文研究的主要是Java编程Retry重试机制实例详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下 1.业务场景 应用中需要实现一个功能: 需要将数据上传到远程存储服务,同时在返回处理成功情况下做其他操作.这个功能不复杂,分为两个步骤:第一步调用远程的Rest服务逻辑包装给处理方法返回处理结果:第二步拿到第一步结果或者捕捉异常,如果出现错误或异常实现重试上传逻辑,否则继续逻辑操作. 2.常规解决方案演化 1)try-catch-redo简单重试模式: 包装正

  • java的异常与处理机制分析【附面试题】

    本文实例讲述了java的异常与处理机制.分享给大家供大家参考,具体如下: java的异常机制 Throwable类 Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别.JDK中内建了一些常用的异常类,我们也可以自定义异常. Throwable又派生出Error类和Exception类. 错误:Error类以及他的子类的实例,代表了JVM本身的错误.错误不能被程序员通过代码处理,Error很少出

  • Java锁机制Lock用法示例

    本文实例讲述了Java锁机制Lock用法.分享给大家供大家参考,具体如下: package com.expgiga.JUC; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 一.用于解决多线程安全问题的方式: * 1.同步代码块 synchronized 隐式锁 * 2.同步方法 synchronized 隐式锁 * 3.同步锁Lock (jdk1.5以后

  • Java的SPI机制实例详解

    Java的SPI机制实例详解 SPI的全名为Service Provider Interface.普通开发人员可能不熟悉,因为这个是针对厂商或者插件的.在java.util.ServiceLoader的文档里有比较详细的介绍.究其思想,其实是和"Callback"差不多."Callback"的思想是在我们调用API的时候,我们可以自己写一段逻辑代码,传入到API里面,API内部在合适的时候会调用它,从而实现某种程度的"定制". 典型的是Colle

  • 深入理解Java原生的序列化机制

    概念 一个对象如果想在硬盘上存储,一定就需要借助于一定的数据格式.这种把对象转换为硬盘存储的格式的过程就叫做对象的序列化,同样地,将这些文件再反向转换为程序中对象的操作就叫做反序列化 一些复杂的解决方案可能是将对象转换为json字符串的方式,这种方式的优点是易读,但是效率还是太低,所以Java的序列化的解决方案是将对象转换为一个二进制流的形式,来实现数据的持久化,本篇文章将会来详细讲解序列化的实现和原理 实现 准备 我们这里有一个普通的对象,要注意的是这个类和其中用到的所有对象都需要实现序列化接

  • 深入学习Java中的SPI机制

    概述 SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现. Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦. SPI整体机制图如下 当服务

  • 深入理解Java中的SPI机制

    本文通过探析JDK提供的,在开源项目中比较常用的Java SPI机制,希望给大家在实际开发实践.学习开源项目提供参考. 1 SPI是什么 SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件. 整体机制图如下: Java SPI 实际上是"基于接口的编程+策略模式+配置文件"组合实现的动态加载机制. 系统设计的各个抽象,往往有很多不同的实现方案,在面向的对象的设计里,一般推荐模块之间基于接

  • Java中的SPI机制案例分享

    目录 1 简单介绍 2 SPI 案例 3 SPI 的原理剖析 1 简单介绍 当我们封装了一套接口,其它项目想要调用我们的接口只需要引入我们写好的包,但是其它项目如果想要对我们的接口进行扩展,由于接口是被封装在依赖包中的,想要扩展并不容易,这时就需要依赖于Java为我们提供的SPI机制. SPI的全称是Service Provider Interface,服务提供者接口,而与之最接近的概念就是API,全称Application Programming Interface,应用程序编程接口.那么这两

  • 一文带你了解Java中的SPI机制

    目录 1: SPI机制简介 2: SPI原理 3: 使用场景 4: 源码论证 5: 实战 6: 优缺点 6.1 优点 6.2 缺点 1: SPI机制简介 SPI 全称是 Service Provider Interface,是一种 JDK 内置的动态加载实现扩展点的机制,通过 SPI 技术我们可以动态获取接口的实现类,不用自己来创建.这个不是什么特别的技术,只是 一种设计理念. 2: SPI原理 Java SPI 实际上是基于接口的编程+策略模式+配置文件组合实现的动态加载机制. 系统设计的各个

  • 在java中使用SPI创建可扩展的应用程序操作

    简介 什么是可扩展的应用程序呢?可扩展的意思是不需要修改原始代码,就可以扩展应用程序的功能.我们将应用程序做成插件或者模块. 这样可以在不修改原应用的基础上,对系统功能进行升级或者定制化. 本文将会向大家介绍如何通过java中的SPI机制实现这种可扩展的应用程序. SPI简介 SPI的全称是Java Service Provider Interface.是java提供的一种服务发现的机制. 通过遵循相应的规则编写应用程序之后,就可以使用ServiceLoader来加载相应的服务了. SPI的实现

  • JAVA中的SPI思想介绍

    目录 1. SPI介绍 2. SPI规则 3. SPI案例 3.1 组件的定义 3.2 组件的实现 3.3 组件的选用 4. SPI原理 5. SPI要求 6. SPI应用 总结 1. SPI介绍 SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,其意义在于为某个接口寻找服务的实现,主要应用在框架中用来寻找组件,提高扩展性. 汽车制造是一个比较繁琐的过程,通常的手段是先规定汽车各个零部件的生产规格,各个零部件厂商按照这种规则去生产

  • 浅析Java中的SPI原理

    在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的"开闭原则".所以我们一般有两种选择:一种是使用API(Application Programming Interface),另一种是SPI(Service Provider Interface),API通常被应用程序开发人员使用,而SPI通常被框架扩展人员使用. 在进入下面学习之前,我们先来再加深一下API和

  • 妙解Java中的回调机制(CallBack)

    前言 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回调之后,再去看网上的各种讲解,确实没什么问题.但是,对于初学的我来说,缺了一个循序渐进的过程. 回调是一种双向调用模式,什么意思呢,就是说,被调用方在被调用时也会调用对方,这就叫回调."If you call me, i will call back". 不理解?没关系,先看看这个可以说比

  • Java中的反射机制详解

    Java中的反射机制详解 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 看概念很晕的,继续往下

  • java 中动态代理机制的实例讲解

    java 中动态代理机制的实例讲解 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾. 在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)

随机推荐