“自动扫描”技术SPI机制详解

Java的SPI机制

一、简介

SPI 机制,英文全称为Service Provider Interface ,字面意思为服务提供者接口,它是JDK提供给"服务提供厂商"或者"插件开发者"使用的接口。

SPI的设计思想:在系统的各个模块中,往往有着多个实现,例如日志,数据库驱动...,其实就是为了在使用某个接口的时候不用指定实现类,可以通过SPI机制来发现和加载这些的实现类,Spring的自动装配也是参考了Java的SPI机制所实现的。


二、SPI实现流程

  1. 定义SPI顶级接口

  2. 创建SPI实现类,可以是一个或者多个

  3. 在resources目录下创建 META-INF 文件夹

    1. META-INF 下创建SPI顶级接口全路径为名称的文件。例:cn.yufire.demo.spi.CarEngine
  4. 将所有SPI实现类的全路径写入此文件中,多个换行分割

  5. 使用java.util包下的ServiceLoader加载所有的API实现类

    1. 调用实现类中实现好的方法

三、SPI的应用场景

目前很多主流的软件都在使用SPI进行开发,例如JDBC的数据库驱动,在各家数据库厂商的提供的驱动中,基本都采用了SPI机制来加载自家的数据库驱动。

  1. 例如MySQL的驱动包
  • 在DriverManager中就能看到加载SPI的地方和代码
scss 复制代码
 static {
   loadInitialDrivers();
   println("JDBC DriverManager initialized");
 }
 ​
 private static void loadInitialDrivers() {
   .....
     AccessController.doPrivileged(new PrivilegedAction<Void>() {
       public Void run() {
         //使用ServiceLoader动态加载具体的驱动实现类
         ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
         Iterator<Driver> driversIterator = loadedDrivers.iterator();
         try{
           while(driversIterator.hasNext()) {
             driversIterator.next();
           }
         } catch(Throwable t) {
           // Do nothing
         }
         return null;
       }
     });
   .....
 }

2.例如日志框架,log4jlogback都是通过SPI机制加载的

3.例如dubbo的负载均衡策略

类似SPI机制的技术例如,Spring Boot的自动装配,其思想也是借鉴与SPI,也是在META-INF包下创建一个名为spring.factories的文件,将需要自动装配的类的全地址写入到这个文件内,就可以实现,自动装配所需要的Bean


四、SPI实现简单实现

1. 首先定义一个服务的顶级通用接口

csharp 复制代码
 package cn.yufire.spi;
 ​
 /**
  * @author Yu
  * @date 2022/5/9 14:55
  * 汽车引擎顶级接口,用于定义顶级SPI接口实现
  */
 public interface CarEngine {
 ​
     /**
      * 装载引擎
      */
     void loadingEngine();
 }

2. 创建SPI顶级接口实现类

为了测试多实现类,所以创建2个SPI接口实现类

  • 创建V8引擎实现类
java 复制代码
 package cn.yufire.spi.impl;
 ​
 import cn.yufire.spi.CarEngine;
 ​
 /**
  * @author Yu
  * @date 2022/5/9 14:58
  * V8发动机SPI实现
  */
 public class V8_Engine implements CarEngine {
     @Override
     public void loadingEngine() {
         System.out.println("v8发动机引擎加载中...");
     }
 }
  • 创建V12引擎实现类
java 复制代码
 package cn.yufire.spi.impl;
 ​
 import cn.yufire.spi.CarEngine;
 ​
 /**
  * @author Yu
  * @date 2022/5/9 14:58
  * v12发动机SPI实现
  */
 public class V12_Engine implements CarEngine {
     @Override
     public void loadingEngine() {
         System.out.println("v12发动机引擎加载中...");
         System.out.println("v12发动机引擎加载完毕! 我是最强的!");
     }
 }

3. 创建存放SPI实现类的文件

  • resources目录下创建 META-INF文件夹
  • META-INF下创建SPI顶级接口类全地址为名称文件

4. 将SPI实现类写入此文件中

  • 多个实现换行隔开即可
rust 复制代码
 cn.yufire.spi.impl.V12_Engine
 cn.yufire.spi.impl.V8_Engine

5. 创建测试类

php 复制代码
 /**
  * @author Yu
  * @date 2022/5/9 15:00
  * spi测试
  */
 public class Tests {
 ​
     public static void main(String[] args) {
         // 获取所有的CarEngine实现类
         ServiceLoader<CarEngine> serviceLoader = ServiceLoader.load(CarEngine.class);
         // 执行所有实现类的loadingEngine方法
         serviceLoader.forEach(CarEngine::loadingEngine);
     }
 }
  • 执行后输出
erlang 复制代码
 v12发动机引擎加载中...
 v12发动机引擎加载完毕! 我是最强的!
 v8发动机引擎加载中...

相关推荐
明月_清风4 小时前
加密解密系统完全指南:原理剖析与 Go 实践
后端
方也_arkling4 小时前
【Java-Day08】static / final / 枚举
java·开发语言
橙淮4 小时前
Spring Bean作用域与生命周期全解析
java·spring
Chengbei114 小时前
一站式源码安全检测工具、云安全 / APP / 小程序源码敏感信息递归多层目录扫描AK、JWT、手机号、身份证等敏感信息
java·开发语言·安全·web安全·网络安全·系统安全·安全架构
llz_1124 小时前
web-第一次课后作业
java·开发语言·idea
秋94 小时前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本4 小时前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
DIY源码阁5 小时前
JavaSwing学生成绩管理系统 - MySQL版
java·数据库·mysql·eclipse
冬奇Lab5 小时前
每日一个开源项目(第105篇):Twenty - 跳出 Salesforce 的圈套,定义现代开源 CRM
前端·后端·开源
basketball6166 小时前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++