Java 中的 SPI

SPI全名为Service Provider Interface

系统设计的各个抽象,往往有很多不同的实现方案,在面向的对象的设计里,一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制
Java SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。所以SPI的核心思想就是解耦

简单实现SPI思想

Java 中的 SPI_第1张图片
java-spi

    <artifactId>java-spiartifactId>
    <packaging>pompackaging>
    <modules>
        <module>service-commonmodule>
        <module>ali-paymodule>
        <module>wx-paymodule>
        <module>main-testmodule>
    modules>

提供服务接口
Java 中的 SPI_第2张图片

public interface PayService {
     
    public void pay();
}

ali-pay、wx-pay分别给予实现
Java 中的 SPI_第3张图片
ali-pay

    <dependencies>
        <dependency>
            <artifactId>service-commonartifactId>
            <groupId>com.ffgroupId>
            <version>1.0-SNAPSHOTversion>
        dependency>
    dependencies>
public class AliPay implements PayService {
     
    @Override
    public void pay() {
     
        System.out.println("支付宝支付");
    }
}

Java 中的 SPI_第4张图片

wx-pay

    <dependencies>
        <dependency>
            <artifactId>service-commonartifactId>
            <groupId>com.ffgroupId>
            <version>1.0-SNAPSHOTversion>
        dependency>
    dependencies>
public class WXPay implements PayService {
     
    @Override
    public void pay() {
     
        System.out.println("微信支付");
    }
}

测试
Java 中的 SPI_第5张图片
ServiceLoader:一个简单的服务提供商加载工具。(具体可查API)
此时打印控制台打印肯定是什么都没有的,因为我们还没有加载具体服务

public class MainTest {
     

    public static void main(String[] args) {
     
        ServiceLoader<PayService> load = ServiceLoader.load(PayService.class);
        for (PayService payService : load) {
     
            System.out.println(payService);
        }
    }
}

来看看ServiceLoader
Java 中的 SPI_第6张图片
按照规范创建文件
Java 中的 SPI_第7张图片
Java 中的 SPI_第8张图片
wx-pay同理
Java 中的 SPI_第9张图片
在这里插入图片描述
main-test还需要添加相关依赖

    <dependencies>
        <dependency>
            <artifactId>service-commonartifactId>
            <groupId>com.ffgroupId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        <dependency>
            <groupId>com.ffgroupId>
            <artifactId>ali-payartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
        <dependency>
            <groupId>com.ffgroupId>
            <artifactId>wx-payartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
    dependencies>

此时测试,服务就可以得到具体的实现
Java 中的 SPI_第10张图片

Java SPI 规范

  1. 当服务提供者提供了接口的一种具体实现后,在 jar 包的 META-INF/services 目录下创建一个以“接口全路径名”为命名的文件,内容为实现类的全限定名;
  2. 接口实现类所在的 jar 包放在主程序的 classpath 中;
  3. 主程序通过 java.util.ServiceLoder 动态装载实现模块,它通过扫描 META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到 JVM;
  4. SPI 的实现类必须携带一个不带参数的构造方法;

你可能感兴趣的:(#,SpringBoot,spring,boot)