Java SPI concept and application implementation

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

insert image description here
insert image description here

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

insert image description here

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

insert image description here
insert image description here

不同于 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:
insert image description here

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

insert image description here

Guess you like

Origin blog.csdn.net/weixin_42176639/article/details/129052913