Java SPI 测试 Demo
- 一.SPI 简介
- 1.概念 SPI 与 API
- 2.作用
- 二.Jdk SPI 实现
- 1.SPI 接口定义
- 2.SPI 实现类定义
- 3.SPI 配置
- 4.测试
- 三.SpringBoot SPI 实现
- 1.引入 SpringBoot 依赖
- 2.SpringBoot SPI 配置
- 3.测试
一.SPI 简介
1.概念 SPI 与 API
SPI 全称:Service Provider Interface (服务提供接口)
API 全称:Application Programming Interface (应用程序接口)
SPI 多用于框架扩展点,在底层代码中应用较多;在 Java 中,JDK 有一套内置的 SPI 程序扩展点,
Java 中 SPI 的使用场景有 Dubbo 、Spring、Logger、JDBC 等;
虽然业务代码中很少使用 SPI ,但是个人认为 SPI 和业务代码中定义的接口与实现,在思想上更一致
而 API 其实就是程序接口,供 UI 或第三方调用的,与 SPI 有着本质区别
2.作用
在应用框架中,作为一组顶层接口,用于为可扩展组件的供应商提供统一接口;方便通过配置指定不同供应商的实现。
以 JDBC 为例,可以利用 SPI 机制方便切换同一数据库的不同驱动实现,或切换不同库的驱动
二.Jdk SPI 实现
1.SPI 接口定义
定义一个动物接口,用于不同动物供应商去实现
package org.example.demo.spi.inter;
/**
* @author moon
* @date 2023-02-15 22:59
* @since 1.8
*/
public interface AnimalSpi {
/**
* 喂养
*/
void feed();
}
2.SPI 实现类定义
猫的实现
package org.example.demo.spi;
import org.example.demo.spi.inter.AnimalSpi;
/**
* @author moon
* @date 2023-02-15 23:03
* @since 1.8
*/
public class Cat implements AnimalSpi {
@Override
public void feed() {
System.out.println("Cats eat fish.");
}
}
狗的实现
package org.example.demo.spi;
import org.example.demo.spi.inter.AnimalSpi;
/**
* @author moon
* @date 2023-02-15 23:02
* @since 1.8
*/
public class Dog implements AnimalSpi {
/**
* 狗吃肉
*/
@Override
public void feed() {
System.out.println("Dogs eat meat.");
}
}
3.SPI 配置
1.SPI 配置文件位置:资源目录下,新建 META-INF 目录,再创建 services 目录
2.SPI 配置文件命名:SPI 接口的全限定名,多个 SPI 接口则创建多个文件,如 org.example.demo.spi.inter.AnimalSpi
3.SPI 配置文件内容:SPI 实现类的全限定名,多个实现则写多行,如 org.example.demo.spi.Dog
4.测试
package org.example.demo;
import org.example.demo.spi.inter.AnimalSpi;
import java.util.ServiceLoader;
/**
* @author moon
* @date 2023-02-15 23:05
* @since 1.8
*/
public class AppSpi {
public static void main(String[] args) {
ServiceLoader<AnimalSpi> loader = ServiceLoader.load(AnimalSpi.class);
loader.forEach(k->{
k.feed();
});
}
}
结果
三.SpringBoot SPI 实现
1.引入 SpringBoot 依赖
上面 Jdk 的 SPI 测试时,未引入额外依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>DynamicDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.2</version>
</dependency>
</dependencies>
</project>
2.SpringBoot SPI 配置
不同于 JDK 的 SPI
SpringBoot 自己实现的 SPI 配置如下
1.SPI 配置文件位置:资源目录下,新建 META-INF 目录
2.SPI 配置文件命名:固定文件名称 spring.factories
3.SPI 配置文件内容:SPI 接口的全限定名,多个接口写多行,每行多个实现用 【,】拼接,如 org.example.demo.spi.Dog,org.example.demo.spi.Cat
多个接口和实现配置如图:
3.测试
package org.example.demo;
import org.example.demo.spi.inter.AnimalSpi;
import org.springframework.core.io.support.SpringFactoriesLoader;
import java.util.List;
/**
* @author moon
* @date 2023-02-15 23:05
* @since 1.8
*/
public class AppSpi {
public static void main(String[] args) {
List<AnimalSpi> spi = SpringFactoriesLoader.loadFactories(AnimalSpi.class,Thread.currentThread().getContextClassLoader());
spi.forEach(k->{
k.feed();
});
}
}
结果