Implementing and Understanding Java's Service Provider Interface

Code Changes Before and After Using SPI

Loading JDBC Driver Implementations

Before adopting the SPI mechanism, establishing a database connection with JDBC typically required explicit driver class loading:

// Manually load the MySQL Driver implementation
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", "user", "pass");

After implementing SPI, DriverManager.getConnection() can be invoked directly without manual class loading.

SLF4J Locating Logging Implementations

Previously, SLF4J required each concrete loggging implementation to provide a specific binder class (org.slf4j.impl.StaticLoggerBinder) to establish the binding, functioning similarly to SPI's configuraton files. With SPI, this binding is achieved through the SLF4JServiceProvider interface.

Practical SPI Implementation Example

Consider an Extension interface. A client uses the ExtensionManager class to load and execute all discovered implementations via its activateExtensions method.

// Extension interface
public interface Extension {
    void activate(Configuration config);
}

public class ExtensionManager {
    public void activateExtensions() {
        Configuration config = new Configuration();
        config.set("beans", new ArrayList<>());
        config.set("version", "2.1.0");
        config.set("features", new HashMap<>());

        // Load all Extension implementations using ServiceLoader
        ServiceLoader<Extension> loader = ServiceLoader.load(Extension.class);
        for (Extension ext : loader) {
            ext.activate(config);
        }
    }

    public static void main(String[] args) {
        ExtensionManager manager = new ExtensionManager();
        manager.activateExtensions();
    }
}

Implementation of the Extension interface:

public class AuditExtension implements Extension {
    private static final Logger LOG = LoggerFactory.getLogger(AuditExtension.class);

    @Override
    public void activate(Configuration config) {
        LOG.debug("Initializing audit extension...");
        // Initialization logic here
    }
}

A key advantage of SPI is the ability to switch implementations without modifying client code. This is done by changing the dependency in the build configuration (e.g., Maven) or replacing the corresponding JAR file in the classpath and restarting the service.

SPI Implementation Mechanism

The ServiceLoader.load() method operates by reading a file named after the fully qualified interface name from the META-INF/services/ directory. This file contains the fully qualified names of the implementing classes. ServiceLoader then loads each class, uses reflection to instantiate it via its no-argument constructor, and returns the instances.

Tags: java SPI ServiceLoader JDBC SLF4J

Posted on Tue, 01 Sep 2026 16:47:54 +0000 by chris9902