Java SPI (Service Provider Interface) is a built-in service discovery mechanism that combines interface programming, strategy pattern, and configuration files to allow dynamic class loading at runtime. SPI is widely used in JDBC, JNDI, logging, XML parsing and other scenarios.

SPI (Service Provider Interface)

SPI Introduction

SPI (Service Provider Interface) is a built-in service provider discovery mechanism in the Java Development Kit (JDK). As a standardized service extension point discovery method, it is currently widely used in various frameworks to implement dynamic service extension.

SPI Working Mechanism

The core idea of SPI is “interface-oriented programming + strategy pattern + configuration file” combined implementation. The specific workflow is:

  1. Define service interface (such as java.sql.Driver)
  2. Create a file named after the interface’s fully qualified name in the META-INF/services/ directory
  3. Write the fully qualified name of the concrete implementation class in that file
  4. Use ServiceLoader class to load and instantiate these implementation classes

Advantages of SPI

  1. Decoupling: Separate service interface from concrete implementation
  2. Extensibility: New service implementations without modifying original code
  3. Dynamic: Service implementations can be dynamically discovered and loaded at runtime
  4. Standardization: As a JDK standard mechanism

Typical Application Scenarios

  1. JDBC database driver loading (java.sql.Driver)
  2. JNDI service provider
  3. XML parser
  4. Logging frameworks
  5. Spring Boot auto-configuration mechanism

Java SPI Usage Explained

1. Standard Service Interface Definition

// Define payment interface standard
package com.example.spi;

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

2. Service Provider Implementation

package com.example.provider;

import com.example.spi.PaymentService;

public class AlipayService implements PaymentService {
    @Override
    public String pay(double amount) {
        return "Alipay payment successful, amount: " + amount;
    }

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

3. Configuration File

File path: META-INF/services/com.example.spi.PaymentService

File content:

com.example.provider.AlipayService

4. Service Caller Usage

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("Discovered payment service: " + service.getPaymentMethod());
        }
    }
}

SPI in Dubbo

Dubbo extensively uses SPI as an extension point. By implementing the same interface, you can customize your own implementation class.

Extension Point Usage

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 specifies a default implementation, which is a fallback mechanism.