Java基础之SPI机制

SPI 机制,全称为 Service Provider Interface,是一种服务发现机制。它通过在 ClassPath 路径下的 META-INF/services 文件夹查找文件,自动加载文件里所定义的类。这一机制为很多框架扩展提供了可能,比如在 Dubbo、JDBC 中都使用到了 SPI 机制。本文介绍了 Java SPI 机制以及在模块化和非模块话项目中的实现方式(此处的模块化指 Java9 引入的模块化)

SPI 机制介绍

SPI 全称 Service Provider Interface,是 Java 提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI 的作用就是为这些被扩展的 API 寻找服务实现。

SPI 和 API 的区别

API (Application Programming Interface)在大多数情况下,都是实现方制定接口并完成对接口的实现,调用方仅仅依赖接口调用,且无权选择不同实现。 从使用人员上来说,API 直接被应用开发人员使用。如下图所示,其中模块 A 为接口制定方和实现方,而模块 B 为接口的使用放。

API概念

维基百科关于 API 的描述:In building applications, an API (application programming interface) simplifies programming by abstracting the underlying implementation and only exposing objects or actions the developer needs. While a graphical interface for an email client might provide a user with a button that performs all the steps for fetching and highlighting new emails, an API for file input/output might give the developer a function that copies a file from one location to another without requiring that the developer understand the file system operations occurring behind the scenes.

SPI (Service Provider Interface)是调用方来制定接口规范,提供给外部来实现,调用方在调用时则选择自己需要的外部实现,可用于启用框架扩展和可替换组件。 从使用人员上来说,SPI 被框架扩展人员使用。如下图所示,A 模块是接口的定义方和使用方,而 B 模块则是接口实现方。

SPI概念

SPI 维基百科定义:Service Provider Interface (SPI) is an API intended to be implemented or extended by a third party. It can be used to enable framework extension and replaceable components

SPI java 官方定义:A service is a well-known set of interfaces and (usually abstract) classes. A service provider(SPI) is a specific implementation of a service. The classes in a provider typically implement the interfaces and subclass the classes defined in the service itself. Service providers can be installed in an implementation of the Java platform in the form of extensions, that is, jar files placed into any of the usual extension directories. Providers can also be made available by adding them to the application’s class path or by some other platform-specific means.

SPI 的优点

使用 Java SPI 机制的优势是实现解耦,使得接口的定义与具体业务实现分离,而不是耦合在一起。应用进程可以根据实际业务情况启用或替换具体组件。以 java 中的 JDBC 数据库驱动为例,java 官方在核心库制定了 java.sql.Driver 数据库驱动接口,使用该接口实现了数据库链接等逻辑,但是并没有具体实现数据库驱动接口,而是交给 MySql 等厂商去实现具体的数据库接口。

引用自博客:Java SPI 主要是应用于厂商自定义组件或插件中。在 java.util.ServiceLoader 的文档里有比较详细的介绍。简单的总结下 java SPI 机制的思想:我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块、xml 解析模块、jdbc 模块等方案。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。 Java SPI 就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似 IOC 的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

SPI 的约定

服务提供方需要通过一些约定告诉系统自己所提供的服务的位置,java9 之后一共有两种约定方式:

  1. 通过在 META-INF/services/ 目录下配置相关文件实现。
  2. 通过 java9 jigsaw 的导出语句指定服务位置。

    A service provider is a single type, usually a concrete class. An interface or abstract class is permitted because it may declare a static provider method, discussed later. The type must be public and must not be an inner class.
    A service provider and its supporting code may be developed in a module, which is then deployed on the application module path or in a modular image. Alternatively, a service provider and its supporting code may be packaged as a JAR file and deployed on the application class path. The advantage of developing a service provider in a module is that the provider can be fully encapsulated to hide all details of its implementation.
    An application that obtains a service loader for a given service is indifferent to whether providers of the service are deployed in modules or packaged as JAR files. The application instantiates service providers via the service loader’s iterator, or via Provider objects in the service loader’s stream, without knowledge of the service providers’ locations.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-御狐神-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值