Java SPI Test Demo
1. Introduction to SPI
1. Concept SPI and API
SPI full name: Service Provider Interface (Service Provider Interface)
API full name: Application Programming Interface (application programming interface)
SPI 多用于框架扩展点,在底层代码中应用较多;在 Java 中,JDK 有一套内置的 SPI 程序扩展点,
Java 中 SPI 的使用场景有 Dubbo 、Spring、Logger、JDBC 等;
虽然业务代码中很少使用 SPI ,但是个人认为 SPI 和业务代码中定义的接口与实现,在思想上更一致
而 API 其实就是程序接口,供 UI 或第三方调用的,与 SPI 有着本质区别
2. Function
在应用框架中,作为一组顶层接口,用于为可扩展组件的供应商提供统一接口;方便通过配置指定不同供应商的实现。
以 JDBC 为例,可以利用 SPI 机制方便切换同一数据库的不同驱动实现,或切换不同库的驱动
2. Jdk SPI implementation
1. SPI interface definition
Define an animal interface for different animal suppliers to implement
package org.example.demo.spi.inter;
/**
* @author moon
* @date 2023-02-15 22:59
* @since 1.8
*/
public interface AnimalSpi {
/**
* 喂养
*/
void feed();
}
2. SPI implementation class definition
cat realization
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.");
}
}
Realization of the dog
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 configuration
1.SPI 配置文件位置:资源目录下,新建 META-INF 目录,再创建 services 目录
2.SPI 配置文件命名:SPI 接口的全限定名,多个 SPI 接口则创建多个文件,如 org.example.demo.spi.inter.AnimalSpi
3.SPI 配置文件内容:SPI 实现类的全限定名,多个实现则写多行,如 org.example.demo.spi.Dog
4. Test
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();
});
}
}
result
3. SpringBoot SPI implementation
1. Introduce SpringBoot dependencies
When testing the SPI of Jdk above, no additional dependencies were introduced
<?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 configuration
不同于 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
Multiple interfaces and implementation configurations are shown in the figure:
3. Test
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();
});
}
}
result