The provides
keyword in Java is part of the Java Platform Module System (JPMS) introduced in Java 9. It is used within a module declaration to specify that the module provides an implementation of a service interface. This keyword is paired with the with
keyword to declare the specific implementation class.
Table of Contents
- Introduction
provides
Keyword Syntax- Understanding
provides
- Examples
- Providing a Service Implementation
- Using the Service
- Real-World Use Case
- Conclusion
Introduction
In Java’s module system, services and service providers are declared and consumed using the provides
and uses
keywords. The provides
keyword is used to declare that a module provides an implementation for a specified service interface.
provides Keyword Syntax
The syntax for using the provides
keyword in a module-info.java
file is as follows:
module moduleName { provides fully.qualified.ServiceInterfaceName with fully.qualified.ImplementationClassName; }
Example:
module com.example.provider { provides com.example.myapp.api.MyService with com.example.provider.MyServiceImpl; }
Understanding provides
Key Points:
- Service Provider: The
provides
keyword declares that the module provides an implementation of a service interface. - Implementation Class: The
with
keyword specifies the class that implements the service interface. - Service Discovery: The
ServiceLoader
class can be used to discover and load implementations of the service at runtime.
Examples
Providing a Service Implementation
A module that provides an implementation for a service interface.
Example
// File: src/com.example.provider/module-info.java module com.example.provider { requires com.example.myapp; provides com.example.myapp.api.MyService with com.example.provider.MyServiceImpl; } // File: src/com.example.myapp/api/MyService.java package com.example.myapp.api; public interface MyService { void performService(); } // File: src/com.example.provider/MyServiceImpl.java package com.example.provider; import com.example.myapp.api.MyService; public class MyServiceImpl implements MyService { @Override public void performService() { System.out.println("Service performed by MyServiceImpl"); } }
Using the Service
Using the ServiceLoader
to load and use the service implementation.
Example
// File: src/com.example.myapp/module-info.java module com.example.myapp { uses com.example.myapp.api.MyService; } // File: src/com.example.myapp/Main.java package com.example.myapp; import com.example.myapp.api.MyService; import java.util.ServiceLoader; public class Main { public static void main(String[] args) { ServiceLoader<MyService> serviceLoader = ServiceLoader.load(MyService.class); for (MyService service : serviceLoader) { service.performService(); } } }
Output:
Service performed by MyServiceImpl
Real-World Use Case
Plugin System
In real-world applications, the provides
and uses
keywords can be used to create a plugin system where the main application can discover and use plugins (service providers) at runtime without knowing the implementation details.
Example
// Main application module definition (src/com.example.app/module-info.java) module com.example.app { uses com.example.plugin.api.Plugin; } // Plugin API module definition (src/com.example.plugin/module-info.java) module com.example.plugin { exports com.example.plugin.api; } // Plugin provider module definition (src/com.example.plugin.impl/module-info.java) module com.example.plugin.impl { requires com.example.plugin; provides com.example.plugin.api.Plugin with com.example.plugin.impl.PluginImpl; } // Plugin interface (src/com.example.plugin/api/Plugin.java) package com.example.plugin.api; public interface Plugin { void execute(); } // Plugin implementation (src/com.example.plugin.impl/PluginImpl.java) package com.example.plugin.impl; import com.example.plugin.api.Plugin; public class PluginImpl implements Plugin { @Override public void execute() { System.out.println("Plugin executed by PluginImpl"); } } // Main application (src/com.example.app/Main.java) package com.example.app; import com.example.plugin.api.Plugin; import java.util.ServiceLoader; public class Main { public static void main(String[] args) { ServiceLoader<Plugin> serviceLoader = ServiceLoader.load(Plugin.class); for (Plugin plugin : serviceLoader) { plugin.execute(); } } }
Output:
Plugin executed by PluginImpl
Conclusion
The provides
keyword in Java’s module system is used for declaring service implementations. By specifying which classes provide implementations for service interfaces, modules can discover and use these implementations at runtime through the ServiceLoader
mechanism. Understanding and using the provides
keyword effectively is essential for developing modular and maintainable Java applications that rely on dynamic service discovery and decoupled architecture.