Master Java SPI: From Service Provider Interface to Spring Boot Auto‑Configuration
This article explains Java’s Service Provider Interface (SPI) mechanism, compares it with traditional APIs, demonstrates how to define interfaces, implement services, and discover them using ServiceLoader, and shows real‑world applications such as Spring Boot auto‑configuration and logging frameworks like SLF4J.
Many interviewers ask about Spring Boot's auto‑configuration and expect the answer to mention Java's SPI (Service Provider Interface) mechanism, the spring.factories file, and the EnableAutoConfiguration annotation.
1. Introduction
SPI stands for Service Provider Interface, which is a service discovery mechanism. In Java, it allows a caller to define an interface that multiple providers can implement, and the runtime can discover those implementations.
Compared with a regular API, SPI emphasizes the contract that the provider must satisfy, and the caller can discover providers without knowing their concrete classes.
2. Defining the Interface
Using a smart‑home air‑conditioner example, we first define a common interface that all air‑conditioner models must implement.
public interface IAircondition {
// Get model type
String getType();
// Turn on/off
void turnOnOff();
// Adjust temperature
void adjustTemperature(int temperature);
// Change mode
void changeModel(int modelId);
}We package this interface into a JAR named aircondition-standard and install it with Maven:
mvn clean install3. Service Implementation
Each air‑conditioner type provides its own implementation and declares the implementation class in META-INF/services/com.cn.hydra.IAircondition.
Hanging‑type implementation:
public class HangingTypeAircondition implements IAircondition {
public String getType() { return "HangingType"; }
public void turnOnOff() { System.out.println("挂式空调开关"); }
public void adjustTemperature(int i) { System.out.println("挂式空调调节温度"); }
public void changeModel(int i) { System.out.println("挂式空调更换模式"); }
}Vertical‑type implementation (similar structure):
public class VerticalTypeAircondition implements IAircondition {
public String getType() { return "VerticalType"; }
public void turnOnOff() { System.out.println("立式空调开关"); }
public void adjustTemperature(int i) { System.out.println("立式空调调节温度"); }
public void changeModel(int i) { System.out.println("立式空调更换模式"); }
}4. Service Discovery
In the consumer application we add the two JARs as dependencies and use ServiceLoader to load all IAircondition implementations.
public class AirconditionApp {
public static void main(String[] args) {
new AirconditionApp().turnOn("VerticalType");
}
public void turnOn(String type) {
ServiceLoader<IAircondition> loader = ServiceLoader.load(IAircondition.class);
for (IAircondition ac : loader) {
System.out.println("检测到:" + ac.getClass().getSimpleName());
if (type.equals(ac.getType())) {
ac.turnOnOff();
}
}
}
}The output shows that both implementations are discovered and the correct one is invoked based on the type parameter.
5. Underlying Principle
The core of SPI is the ServiceLoader class. It lazily loads provider names from META-INF/services, caches them, and creates instances via reflection when iterator() is traversed. The iterator first checks an internal cache ( providers) and then falls back to a LazyIterator that reads the configuration files.
6. Real‑World Applications
SPI is widely used in logging frameworks. For example, SLF4J is a façade that relies on SPI to bind to a concrete logger such as Log4j2 or Reload4j. The binding JAR contains a provider class listed in META-INF/services/org.slf4j.spi.SLF4JServiceProvider, which SLF4J loads at runtime.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>2.0.3</version>
</dependency>The binding JAR’s META-INF/services directory registers Reload4jServiceProvider, which implements SLF4JServiceProvider and supplies the actual LoggerFactory and Logger instances.
7. Summary
Java’s SPI offers a flexible service‑discovery mechanism that decouples callers from providers, making it easy to extend frameworks such as Spring Boot and SLF4J. Its drawback is that loading an interface may instantiate all providers, potentially pulling in unnecessary classes, but overall it provides a powerful pattern for modular architecture.
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.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.
