All topics
library
advanced

ServiceLoader & SPI (Service Provider Interface)

Use Java's built-in plugin mechanism to discover and load implementations at runtime.

ServiceLoader finds implementations of an interface at runtime, from whatever is on the path.

ServiceLoader = a universal power adapter standard. Your device (service consumer) uses a standard plug shape (interface). Any country's outlet (provider) that matches the standard works. New outlets can be added without changing the device — just plug in.

Key Concepts

1
    // the contract, in your API module
    public interface PaymentProvider { String name(); void charge(long amount); }
2
    // in the provider jar: META-INF/services/com.shop.PaymentProvider
    com.stripe.StripeProvider
    com.razorpay.RazorpayProvider
3
    // discovery, with no compile-time dependency on either
    for (PaymentProvider p : ServiceLoader.load(PaymentProvider.class)) {
      register(p.name(), p);
    }
4
The file name is the interface's fully qualified name. Its contents are one implementation class per line. Get either wrong and you simply find nothing — no error, no warning, which is what makes this frustrating to debug.
5
What it gives you. Dropping a jar on the classpath adds a provider. No configuration, no code change, and your module never imports the implementation.
6
Where the JDK uses it.
    JDBC drivers        why Class.forName("...Driver") is obsolete
    Charset providers
    java.util.logging implementations
    Filesystem providers   a zip or in-memory Path
7
JDBC is the clearest before-and-after. You used to load the driver class by name to trigger its static registration block. Since JDBC 4, DriverManager runs a ServiceLoader and the driver jar declares itself.
DriverManagerServiceLoader
8
The requirements for a provider. A public no-argument constructor, and the class must implement the interface. ServiceLoader instantiates it reflectively, so a missing default constructor is a runtime failure.
ServiceLoader
9
It is lazy. Iterating constructs each provider as you reach it, and ServiceConfigurationError is thrown at that point if one cannot be loaded — not when load was called.
ServiceConfigurationErrorload
10
With modules, declare it instead of using a file.
    // in the provider's module-info.java
    provides com.shop.PaymentProvider with com.stripe.StripeProvider;
11
    // in the consumer's
    uses com.shop.PaymentProvider;
12
The uses clause is required, or the module system will not let you load anything.
uses
13
Reload if the classpath can change: loader.reload() discards the cache. Rarely needed outside application servers.
loader.reload()
14
What the interviewer is probing.1. "How does ServiceLoader find implementations?" Probing: the mechanism. Stalls: "Annotations." Moves up: a file in META-INF/services named after the interface, listing implementation class names, one per line.
15
2. "Why is Class.forName no longer needed for JDBC drivers?" Probing: the concrete example. Stalls: "It still is." Moves up: since JDBC 4 DriverManager uses ServiceLoader and the driver jar declares itself, so loading the class by name is obsolete.
16
3. "Your provider is not found and there is no error. Why?" Probing: the silent failure. Stalls: "It must be a classpath issue." Moves up: the file name must be the fully qualified interface name; get it wrong and discovery simply finds nothing, with no warning.
17
4. "How does this change under modules?" Probing: the module syntax. Stalls: "It does not." Moves up: provides ... with ... in the provider and uses ... in the consumer, and without the uses clause the module system will not load anything.