14.3.2 ServiceLoader Class Explained
The ServiceLoader
class in Java SE 11 is a powerful tool for discovering and loading service providers dynamically. It is part of the Java Platform Module System (JPMS) and is used to implement the Service Provider Interface (SPI) pattern. Understanding the ServiceLoader
class is essential for creating modular and extensible applications.
Key Concepts
1. Service Provider Interface (SPI)
The SPI is a design pattern that allows service providers to be discovered and loaded at runtime. It involves defining a service interface and multiple implementations of that interface. The ServiceLoader
class is used to discover and load these implementations dynamically.
Example
// Service interface public interface Logger { void log(String message); } // Service provider implementation public class ConsoleLogger implements Logger { @Override public void log(String message) { System.out.println(message); } }
2. ServiceLoader Class
The ServiceLoader
class is part of the java.util
package and is used to load service providers. It provides a simple and flexible way to discover and instantiate service providers at runtime. The ServiceLoader
class uses the module system to locate and load service providers.
Example
ServiceLoader<Logger> loader = ServiceLoader.load(Logger.class); for (Logger logger : loader) { logger.log("Hello, World!"); }
3. Service Provider Configuration
Service providers are configured using a special file named META-INF/services/fully.qualified.service.interface
. This file contains the fully qualified names of the service provider classes. The ServiceLoader
class uses this file to discover and load the service providers.
Example
// File: META-INF/services/com.example.Logger com.example.ConsoleLogger
4. ServiceLoader Methods
The ServiceLoader
class provides several methods for loading and iterating over service providers. The most commonly used methods are load()
and iterator()
. The load()
method is used to create a ServiceLoader
instance, and the iterator()
method is used to iterate over the discovered service providers.
Example
ServiceLoader<Logger> loader = ServiceLoader.load(Logger.class); Iterator<Logger> iterator = loader.iterator(); while (iterator.hasNext()) { Logger logger = iterator.next(); logger.log("Hello, World!"); }
5. ServiceLoader and Modules
In the context of the Java Platform Module System (JPMS), the ServiceLoader
class is used to discover and load service providers across modules. The provides
and uses
directives in the module descriptor are used to declare service providers and consumers, respectively.
Example
// Service provider module module com.example.logger { provides com.example.Logger with com.example.ConsoleLogger; } // Service consumer module module com.example.app { uses com.example.Logger; }
Examples and Analogies
Think of the ServiceLoader
class as a dynamic plugin system for your application. Just as a plugin system allows you to add new features to an application without modifying its core code, the ServiceLoader
class allows you to add new service providers dynamically. For example, if you are building a logging system, you can use the ServiceLoader
class to load different logging providers (e.g., console, file, database) at runtime.
For instance, in a modular application, you might have multiple modules providing different implementations of a service interface. The ServiceLoader
class allows you to discover and use these implementations dynamically, making your application more flexible and extensible.
By mastering the ServiceLoader
class, you can create more modular, extensible, and maintainable Java applications, aligning with modern software development practices and enhancing your skills as an Oracle Certified Professional Java SE 11 Developer.