
Durgesh Tiwari
Author
The ServiceLoader API in Java is used to load service implementations dynamically at runtime. It is a key part of the SPI (Service Provider Interface) model and works well with the Java Module System (JPMS).
It helps developers build applications that are flexible, scalable, and plugin-based, without tightly coupling different parts of the system.
The ServiceLoader API is a built-in Java feature that is used to discover and load service implementations automatically at runtime.
It is mainly used in modular and plugin-based systems where implementations are not directly hardcoded.
What it does
Automatically finds service implementations
Loads classes at runtime instead of compile time
Helps build flexible and extensible applications
In simple words: ServiceLoader automatically finds and loads implementations at runtime.
SPI is the foundation of the ServiceLoader API in Java.
SPI (Service Provider Interface) is a design approach where:
A service interface is defined (the contract)
Multiple implementations are created for that interface
Java loads the required implementation dynamically at runtime, instead of hardcoding it
Service Interface → defines what needs to be done
Service Provider → actual implementations
Service Loader → finds and loads the correct implementation
Instead of directly writing:
new UpiPayment();
new CardPayment();We let Java decide which implementation should be used at runtime, based on configuration or module setup.

In simple words: SPI allows flexible systems where implementations can be plugged in without changing the core code.
In Java Modules, SPI support is implemented using two important keywords: provides and uses.
The provides keyword is used by the provider module to register service implementations.
module com.app.payment {
exports com.app.service;
provides com.app.service.PaymentService
with com.app.impl.UpiPayment,
com.app.impl.CardPayment;
}here,
This module provides implementations of PaymentService
These classes act as service providers
The uses keyword is used by the consumer module to declare that it will use a service.
module com.app.client {
requires com.app.payment;
uses com.app.service.PaymentService;
}here,
This module depends on PaymentService
Java will load the implementation dynamically at runtime

One of the biggest advantages of the ServiceLoader API is that it allows implementations to be loaded at runtime instead of being hardcoded.
A service interface is defined
Multiple implementations are created
Java discovers available implementations automatically
Objects are instantiated at runtime when needed
Example
ServiceLoader<PaymentService> loader =
ServiceLoader.load(PaymentService.class);
for (PaymentService service : loader) {
service.pay(500);
}👉 Here, Java automatically detects and loads all available implementations of PaymentService at runtime.
ServiceLoader is widely used in plugin-based systems where functionality can be extended without changing the core application.
Service Interface (Contract)
public interface PaymentService {
void pay(double amount);
}Plugins (Implementations)
UPI Payment Plugin
Card Payment Plugin
PayPal Plugin
Each plugin provides its own implementation of the PaymentService.
Main Application
It does not depend on any specific implementation
It automatically detects and loads available plugins at runtime
New plugins can be added without modifying existing code

New features can be added without modifying the core system
Easy to scale and extend functionality
Supports independent development of modules or plugins
Keeps code clean with proper separation of concerns
The ServiceLoader API and SPI concept are widely used in many real-world Java frameworks and systems to support flexibility and extensibility.
JDBC (Java Database Connectivity)
Database drivers are loaded dynamically using SPI
No need to hardcode database-specific implementations
Logging Frameworks
Frameworks like SLF4J and Logback use SPI
They dynamically load logging implementations based on configuration
Application Servers
Servers load modules and plugins dynamically at runtime
Helps support different deployments and extensions
Spring Boot (Indirect Usage)
Uses similar SPI-like mechanisms internally
Helps in auto-configuration and extensibility
Java Cryptography (JCA)
Security providers are loaded dynamically using SPI
Allows multiple encryption implementations to be plugged in

Reduces tight coupling between modules
New implementations can be added easily
No need to modify existing code for extensions
Supports plugin-based architecture naturally
Provides flexibility at runtime
Encourages clean and modular design
A service interface is defined in a module
One or more provider modules implement that interface
The provides keyword registers those implementations
The consumer module declares the service using uses
ServiceLoader automatically loads the available implementations at runtime
The ServiceLoader API (SPI in Java Modules) is a powerful feature that enables Java applications to load implementations dynamically at runtime.
It helps developers build:
Modular applications
Plugin-based systems
Flexible architectures
Scalable enterprise software
Understanding ServiceLoader is very important for modern Java development, interviews, and real-world backend systems.