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
providesKeyword 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
provideskeyword declares that the module provides an implementation of a service interface. - Implementation Class: The
withkeyword specifies the class that implements the service interface. - Service Discovery: The
ServiceLoaderclass 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.