Unlocking Java, Spring, and Dubbo SPI: Principles, Differences, and Real-World Usage
This article explains the Service Provider Interface (SPI) concept and compares the implementations in Java (ServiceLoader), Spring (SpringFactoriesLoader), and Dubbo (ExtensionLoader), covering their configuration files, core mechanisms, advantages, drawbacks, and typical usage scenarios.
Java technology attack site: http://www.susan.net.cn
Hello, I am Su San.
Today we discuss the principles and differences of the SPI mechanisms in Java, Spring, and Dubbo.
What is SPI
SPI (Service Provider Interface) is a dynamic discovery mechanism that decouples interfaces from implementations, allowing third‑party implementations to be plugged in via configuration files, thus enhancing framework extensibility.
Java SPI Mechanism – ServiceLoader
ServiceLoader is Java's simple SPI implementation. It follows two conventions:
Configuration files must reside under META-INF/services/.
File name must be the fully‑qualified interface name, and the file content must list fully‑qualified implementation class names.
Demo
Step 1: Define an interface and its implementation.
public interface LoadBalance {
}
public class RandomLoadBalance implements LoadBalance {
}Step 2: Create a file named with the interface's fully‑qualified name under META-INF/services/ containing the implementation's fully‑qualified name.
Test class:
public class ServiceLoaderDemo {
public static void main(String[] args) {
ServiceLoader<LoadBalance> loader = ServiceLoader.load(LoadBalance.class);
Iterator<LoadBalance> iterator = loader.iterator();
while (iterator.hasNext()) {
LoadBalance lb = iterator.next();
System.out.println("Loaded load‑balance strategy: " + lb);
}
}
}Running the test prints the loaded implementation.
In framework design, the framework author writes this code internally; users only need to provide the interface implementation and the SPI file.
Implementation Principle
The core of ServiceLoader reads the file META-INF/services/<interface‑fqcn> via an InputStream, parses the class name, and instantiates the class via reflection.
Pros and Cons
Pros: Simple and decoupled.
Cons: All implementations are instantiated eagerly, wasting resources, and there is no built‑in way to select a specific implementation without additional logic.
Use Cases
When every loaded implementation must be used.
When a specific implementation can be chosen via interface design (e.g., strategy pattern).
Spring SPI Mechanism – SpringFactoriesLoader
Spring provides its own SPI implementation via SpringFactoriesLoader. The conventions are:
The configuration file must be META-INF/spring.factories.
The file contains key‑value pairs; a key may have multiple comma‑separated values, all being fully‑qualified class names.
Demo
Create META-INF/spring.factories with LoadBalance=RandomLoadBalance.
Test class:
public class SpringFactoriesLoaderDemo {
public static void main(String[] args) {
List<LoadBalance> lbs = SpringFactoriesLoader.loadFactories(LoadBalance.class, MyEnableAutoConfiguration.class.getClassLoader());
for (LoadBalance lb : lbs) {
System.out.println("Loaded LoadBalance object: " + lb);
}
}
}Running the test prints the loaded implementation.
Core Principle
SpringFactoriesLoader reads META-INF/spring.factories, parses the key‑value pairs, and loads the classes.
Use Cases in Spring Boot
1. Auto‑configuration (pre‑Spring Boot 3.0 uses spring.factories).
2. PropertySourceLoader loading (Properties and YAML implementations are discovered via SPI).
Comparison with Java SPI
Spring simplifies Java SPI by using a single spring.factories file, allowing arbitrary key‑value pairs, and providing a method loadFactoryNames to retrieve class names, which Java SPI lacks.
Dubbo SPI Mechanism – ExtensionLoader
Dubbo’s SPI implementation uses ExtensionLoader. Each interface has its own ExtensionLoader instance.
Conventions:
The interface must be annotated with @SPI.
Configuration files can be placed under META-INF/services/, META-INF/dubbo/internal/, META-INF/dubbo/, or META-INF/dubbo/external/, named with the interface’s fully‑qualified name.
File content is a key‑value pair where the key is a short name and the value is the implementation’s fully‑qualified name.
Demo
Annotate the interface:
@SPI
public interface LoadBalance {
}Place random=com.sanyou.spi.demo.RandomLoadBalance in META-INF/services/.
public class ExtensionLoaderDemo {
public static void main(String[] args) {
ExtensionLoader<LoadBalance> loader = ExtensionLoader.getExtensionLoader(LoadBalance.class);
LoadBalance lb = loader.getExtension("random");
System.out.println("Got implementation for key 'random': " + lb);
}
}This solves the problem of selecting a specific implementation.
Dubbo Core Mechanisms
1. Adaptive Extension
Only one adaptive class per interface; getAdaptiveExtension() returns it, and it selects the concrete implementation at runtime based on parameters.
@Adaptive
public class RandomLoadBalance implements LoadBalance {
}Dubbo can also generate an adaptive class automatically.
2. IOC and AOP
Dubbo performs lightweight dependency injection (setter injection) and supports wrapper classes for static AOP.
public class RoundRobinLoadBalance implements LoadBalance {
private LoadBalance loadBalance;
public void setLoadBalance(LoadBalance loadBalance) { this.loadBalance = loadBalance; }
}Wrapper classes have a single‑argument constructor of the interface type.
public class RoundRobinLoadBalance implements LoadBalance {
private final LoadBalance loadBalance;
public RoundRobinLoadBalance(LoadBalance loadBalance) { this.loadBalance = loadBalance; }
}3. Automatic Activation
Classes annotated with @Activate are automatically selected based on input parameters via getActivateExtension(). This is heavily used in Dubbo’s filter chain.
@Activate
public interface RandomLoadBalance {
}Filters can be activated for provider or consumer side based on the activation criteria.
Summary
The core of all SPI mechanisms is reading a designated file via I/O, parsing the class names, and instantiating them. Java’s SPI is simple and lacks extra features. Spring builds on Java’s SPI, adding key‑value configuration and integration with its IoC/AOP. Dubbo extends the concept further, providing adaptive extensions, wrappers, automatic activation, and richer integration to meet its framework needs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
