Java SPI(Service Provider Interface)是一种内置的服务发现机制,结合接口编程、策略模式和配置文件,允许在运行时动态加载实现类。SPI广泛用于 JDBC、JNDI、日志、XML 解析等场景。

SPI (Service Provider Interface)

SPI 简介

SPI(Service Provider Interface)是 Java 开发工具包(JDK)内置的一种服务提供发现机制。它作为一种标准化的服务扩展点发现方式,目前被广泛应用于各种框架中来实现服务的动态扩展。

SPI 工作机制

SPI 的核心思想是”面向接口编程+策略模式+配置文件”的组合实现。具体工作流程为:

  1. 定义服务接口(如java.sql.Driver
  2. META-INF/services/目录下创建以接口全限定名命名的文件
  3. 在该文件中写入具体实现类的全限定名
  4. 通过ServiceLoader类加载并实例化这些实现类

SPI 的优势

  1. 解耦性:将服务接口与具体实现分离
  2. 扩展性:新增服务实现无需修改原有代码
  3. 动态性:服务实现可以在运行时动态发现和加载
  4. 标准化:作为 JDK 标准机制

典型应用场景

  1. JDBC 数据库驱动加载(java.sql.Driver
  2. JNDI 服务提供者
  3. XML 解析器
  4. 日志框架
  5. Spring Boot 自动配置机制

Java SPI 使用详解

1. 标准服务接口定义

// 定义支付接口标准
package com.example.spi;

public interface PaymentService {
    String pay(double amount);
    String getPaymentMethod();
}

2. 服务提供者实现

package com.example.provider;

import com.example.spi.PaymentService;

public class AlipayService implements PaymentService {
    @Override
    public String pay(double amount) {
        return "支付宝支付成功,金额:" + amount;
    }

    @Override
    public String getPaymentMethod() {
        return "Alipay";
    }
}

3. 配置文件

文件路径:META-INF/services/com.example.spi.PaymentService

文件内容:

com.example.provider.AlipayService

4. 服务调用者使用

import com.example.spi.PaymentService;
import java.util.ServiceLoader;

public class PaymentApp {
    public static void main(String[] args) {
        ServiceLoader<PaymentService> services = ServiceLoader.load(PaymentService.class);

        for (PaymentService service : services) {
            System.out.println("发现支付服务: " + service.getPaymentMethod());
        }
    }
}

Dubbo中的SPI

dubbo 中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。

扩展点使用

package icu.wzk.service;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI;

@SPI("dog")
public interface WzkHelloService {
    String sayHello(String name);

    @Adaptive
    String sayHello(URL url);
}

PS:SPI指定一个默认实现,属于一个兜底机制。