Java的SPI机制以及基于SPI编程示例详解

 更新时间:2023年08月25日 11:15:37   作者:jacheut  
这篇文章主要为大家介绍了Java的SPI机制以及基于SPI编程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

背景

在面向对象的设计原则中,一般推荐模块之间基于接口编程,通常情况下调用方模块是不会感知到被调用方模块的内部具体实现。一旦代码里面涉及具体实现类,就违反了开闭原则。如果需要替换一种实现,就需要修改代码。

为了实现在模块装配的时候不用在程序里面动态指明,这就需要一种服务发现机制。Java SPI 就是提供了这样一个机制:为某个接口寻找服务实现的机制。这有点类似 IOC 的思想,将装配的控制权移交到了程序之外。

SPI 英文为 Service Provider Interface, 字面意思就是:“服务提供者的接口”,可以理解为专门提供给服务调用者或者扩展框架功能的开发者去使用的一个接口。

SPI 将服务接口和具体的服务实现分离开来,将服务调用方和服务实现者解耦,能够提升程序的扩展性、可维护性。修改或者替换服务实现并不需要修改调用方。

使用场景

很多框架都使用了 Java 的 SPI 机制,比如:数据库加载驱动,日志接口,以及 dubbo 的扩展实现等等。拿日志接口来说,Spring框架提供的日志服务 SLF4J 其实只是一个日志接口,但是 SLF4J 的具体实现可以有几种,比如:Logback、Log4j、Log4j2 等等,而且还可以切换,在切换日志具体实现的时候我们是不需要更改项目代码的,只需要在 Maven 依赖里面修改一些 pom 依赖就好了。

与API的区别

API:是指可以用来完成某项功能的类、接口或者方法。提供方提供实现方式,调用方只需调用即可。

SPI:是指用来继承、扩展,完成自定义功能的类、接口或者方法。调用方可选择使用提供方提供的内置实现,也可以自己实现。

SPI原理

Java SPI的具体约定为:当服务的提供者提供了服务接口后,在jar包的META-INF/services目录下同时创建一个以服务接口全类名命名的文件,该文件的内容就是实现该服务接口具体实现类的全名,当然这个服务接口实现类也必须在这个jar中。当外部程序装配这个模块的时候,就能通过该jar包META-INF/services下的配置文件找到具体的实现类,并装载实例化,完成模块的注入。Java就是通过扫描META-INF/services文件夹目录下面的文件,把实现类加载到servciceLoader里面。

简单来讲,META-INF/services/下的配置文件名字就是接口的全类名,实现类的全类名就是问这个文件的内容,如果有多个

实现类,可以全部写在这个文件中,同时在实现类中要实现这个接口。

不定义在META-INF/services下面行不行?就想定义在别的地方可以吗?

答案是不行。看下图JDK源码中,因为已经定义为配置路径,如果写在别的地方,类加载器就会找不到了。

案例实现

代码结构如下:

├─main
│ ├─java
│ │ └─com
│ │ ├─test
│ │ │ └─Apple
│ │ │ └─Fruit
│ └─resources
│ ├─META-INF
│ │ └─services
│ │ └─com.test.Fruit

  • 创建接口Fruit,模拟服务提供方接口
package com.test;
public interface Fruit {
}
  • 创建接口实现类Apple,实现Fruit接口;
package com.test;
public class Apple implements Fruit {
    static {
        System.out.println("hi,I am an apple!");
    }
}
  • 在resources结构下创建META-INF/services目录,在这个目录下,创建以这个接口名命名的文件com.test.Fruit,同时在这个文件中写入这个实现类的全类名;
com.test.Apple
  • 创建Test测试类,在测试类中创建一个类加载器ServiceLoader来实现本案例。
import com.test.Fruit;
import java.util.ServiceLoader;
public class Test {
    public static void main(String[] args) {
        ServiceLoader<Fruit> test = ServiceLoader.load(Fruit.class);
        for (Fruit item:test){
        }
    }
}

执行结果如下,表明本案例成功执行。

hi,I am an apple!

以上就是Java的SPI机制以及基于SPI编程示例详解的详细内容,更多关于Java SPI机制的资料请关注脚本之家其它相关文章!

相关文章

  • Java实战项目 医院预约挂号系统

    Java实战项目 医院预约挂号系统

    本文是一个Java语言编写的实战项目,是一个医院预约挂号系统,主要用到了jdbc+jsp+mysql+ajax等技术,技术含量比较高,感兴趣的童鞋跟着小编往下看吧
    2021-09-09
  • 详解Maven 搭建spring boot多模块项目(附源码)

    详解Maven 搭建spring boot多模块项目(附源码)

    这篇文章主要介绍了详解Maven 搭建spring boot多模块项目(附源码),具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • @Qualifier使用及详细源码展示

    @Qualifier使用及详细源码展示

    @Qualifier是Spring解决依赖注入歧义的注解,通过限定符名称指定具体Bean,与@Primary不同,可覆盖主Bean,适用于多实现类和自定义限定符场景,需注意大小写敏感及字段注入的耦合问题,配合@Autowired提升灵活性
    2025-09-09
  • Spring MVC 自定义数据转换器的思路案例详解

    Spring MVC 自定义数据转换器的思路案例详解

    本文通过两个案例来介绍下Spring MVC 自定义数据转换器的相关知识,每种方法通过实例图文相结合给大家介绍的非常详细,需要的朋友可以参考下
    2021-09-09
  • javaWEB中前后台乱码问题的解决方法总结

    javaWEB中前后台乱码问题的解决方法总结

    下面小编就为大家带来一篇javaWEB中前后台乱码问题的解决方法总结。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 详谈Array和ArrayList的区别与联系

    详谈Array和ArrayList的区别与联系

    下面小编就为大家带来一篇详谈Array和ArrayList的区别与联系。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • java连接Mongodb实现增删改查

    java连接Mongodb实现增删改查

    这篇文章主要为大家详细介绍了java连接Mongodb实现增删改查,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • JDK(免安装)各种版本下载及配置详细图文教程

    JDK(免安装)各种版本下载及配置详细图文教程

    这篇文章主要给大家介绍了关于JDK(免安装)各种版本下载及配置的相关资料,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-07-07
  • 学java得这样学,学习确实也得这样

    学java得这样学,学习确实也得这样

    学java得这样学,学习东西确实也得这样
    2008-02-02
  • JAVA-4NIO之Channel之间的数据传输方法

    JAVA-4NIO之Channel之间的数据传输方法

    下面小编就为大家带来一篇JAVA-4NIO之Channel之间的数据传输方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06

最新评论