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:
- Define service interface (such as
java.sql.Driver) - Create a file named after the interface’s fully qualified name in the
META-INF/services/directory - Write the fully qualified name of the concrete implementation class in that file
- Use
ServiceLoaderclass to load and instantiate these implementation classes
Advantages of SPI
- Decoupling: Separate service interface from concrete implementation
- Extensibility: New service implementations without modifying original code
- Dynamic: Service implementations can be dynamically discovered and loaded at runtime
- Standardization: As a JDK standard mechanism
Typical Application Scenarios
- JDBC database driver loading (
java.sql.Driver) - JNDI service provider
- XML parser
- Logging frameworks
- 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.