Fundamentals 9 min read

Understanding Java Service Provider Interface (SPI): Introduction, Example, and Implementation Details

This article introduces Java's Service Provider Interface (SPI), demonstrates a step‑by‑step example with multiple Maven modules, explains how to create interface and implementation classes, configure META‑INF/services files, and delves into the ServiceLoader internals that enable runtime discovery and instantiation of providers.

JD Tech Talk
JD Tech Talk
JD Tech Talk
Understanding Java Service Provider Interface (SPI): Introduction, Example, and Implementation Details

Java's Service Provider Interface (SPI) is a mechanism that decouples an interface from its implementations, allowing the system to discover and load providers at runtime without hard‑coded dependencies.

The tutorial builds four Maven projects: spi-interface (defines Person ), spi-impl1 (implements Teacher ), spi-impl2 (implements Student ), and spi-test (loads implementations via ServiceLoader ).

The interface is defined as:

package com.jd.spi;
public interface Person {
    String favorite();
}

Implementation classes:

package com.jd.spi;
public class Teacher implements Person {
    public String favorite() { return "老师喜欢给学生上课"; }
}

package com.jd.spi;
public class Student implements Person {
    public String favorite() { return "学生喜欢努力学习"; }
}

Each implementation module contains a META-INF/services/com.jd.spi.Person file listing the fully‑qualified class name of its provider, enabling ServiceLoader to locate them.

The test module adds Maven dependencies on the three modules and includes a test class:

package com.jd.spi;
import java.util.Iterator;
import java.util.ServiceLoader;
public class SPITest {
    public static void main(String[] args) {
        ServiceLoader
loader = ServiceLoader.load(Person.class);
        for (Iterator
it = loader.iterator(); it.hasNext(); ) {
            Person p = it.next();
            System.out.println(p.favorite());
        }
    }
}

Running the test prints the favorite strings from both Teacher and Student , confirming that SPI successfully discovered both providers.

The article then examines the core of ServiceLoader : the static PREFIX = "META-INF/services/" , the providers cache, and the lookupIterator . It shows the iterator implementation, the lazy loading logic, and the reflective instantiation performed in nextService() , including security checks via AccessController .

Finally, the workflow is summarized: create the service interface, provide implementations, add configuration files under META-INF/services , and use ServiceLoader.load() to iterate over providers. Key points include the requirement for a no‑arg constructor in providers and the necessity of placing the fully‑qualified interface name file in the classpath.

Backenddesign patternsJavadependency injectionSPIServiceLoader
JD Tech Talk
Written by

JD Tech Talk

Official JD Tech public account delivering best practices and technology innovation.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.