ServiceLoader locates implementations registered for a service interface. Iteration can fail when provider metadata, construction, or linkage is broken.
Java ServiceLoader: treat provider discovery as fallible startup work
Operational contract
The loader selects one provider during startup and converts ServiceConfigurationError into a clear configuration failure. It does not silently skip a broken provider, because doing so could change the selected receipt codec. The classpath registration file or named-module provides directive belongs in the deployment artifact; a service interface alone does not register implementations. ServiceLoader lazily discovers and instantiates providers, so moving iteration into a request path can turn a packaging problem into a customer-visible failure. If multiple providers are legal, selection needs an explicit stable policy.
Failure case
A deployment lists a provider whose constructor throws. The service fails initialization instead of pretending no codec exists and processing receipts with an unintended fallback.
Java code
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
public class ReceiptCodecDiscovery {
public interface ReceiptCodec { byte[] encode(String receipt); }
public static ReceiptCodec requiredProvider() {
try {
Iterator<ReceiptCodec> providers = ServiceLoader.load(ReceiptCodec.class).iterator();
if (!providers.hasNext())
throw new IllegalStateException("No receipt codec registered");
ReceiptCodec selected = providers.next();
if (providers.hasNext())
throw new IllegalStateException("Multiple receipt codecs registered");
return selected;
} catch (ServiceConfigurationError broken) {
throw new IllegalStateException("Receipt codec registration is invalid", broken);
}
}
}Performance and ownership cost
Discovery scans P registered providers and instantiates at least those visited, costing O(P) startup time and provider-dependent memory; this sample visits enough to reject a second provider. Holding the selected provider afterward makes per-request discovery cost O(0).
Common Mistakes
- Do not expect an interface declaration to register a provider.
- Do not swallow ServiceConfigurationError and select a different provider without policy.
- Do not repeat lazy discovery on every request when providers are deployment configuration.
