library
advancedServiceLoader & 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.RazorpayProvider3
// 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 Path7
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.