Java 9 provides another option for the service provide module, that is to provide a class with public static method named 'provider()' which can return the service implementation.
From java.util.ServiceLoader API docs:
A service provider that is developed in a module has no control over when it is instantiated, since that occurs at the behest of the application, but it does have control over how it is instantiated:
- If the service provider declares a provider method, then the service loader invokes that method to obtain an instance of the service provider. A provider method is a public static method named "provider" with no formal parameters and a return type that is assignable to the service's interface or class.
In this case, the service provider itself need not be assignable to the service's interface or class.
With this option provider's module-info.java will look like:
module msg.service.provider.swing {
......
provides service.api.AService with service.provider.TheServiceProvider;
...
}
Where TheServiceProvider class has the provider() method with following signature:
......
public class TheServiceProvider {
public static AService provider() {
return new AServiceImpl();
}
......
}
This option can be preferable for the scenarios where we want to have more control over how the service implementation is initiated. For example, we can initialize the service implementation with some dynamic information or since we can have the service implementation instance handle, we can use or pass it to some other component/observer etc.
Example
Here we are going to reuse our last example. We will just need to modify our provider module, the rest is going to be same.
The Service API
msg.service.api/src/msg/service/MsgService.javapackage msg.service;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
public interface MsgService {
static List<MsgService> getInstances() {
ServiceLoader<MsgService> services = ServiceLoader.load(MsgService.class);
List<MsgService> list = new ArrayList<>();
services.iterator().forEachRemaining(list::add);
return list;
}
void showMessage(String msg);
}
msg.service.api/src/module-info.javamodule msg.service.api {
exports msg.service;
uses msg.service.MsgService;
}
Compiling the class:
D:\service-provider-method-example\msg.service.api>javac -d out src/module-info.java src/msg/service/MsgService.java
Creating the jar:
D:\service-provider-method-example\msg.service.api>jar --create --file msg-service.jar -C out .
The Service Provider
msg.service.provider.swing/src/msg/provider/swing/MsgServiceProvider.javapackage msg.provider.swing;
import msg.service.MsgService;
import javax.swing.*;
public class MsgServiceProvider {
public static MsgService provider() {
return new MsgServiceProviderImpl();
}
private static class MsgServiceProviderImpl implements MsgService {
@Override
public void showMessage(String msg) {
JOptionPane.showMessageDialog(null, "From Msg Provider: " + msg);
}
}
}
msg.service.provider.swing/src/module-info.javamodule msg.service.provider.swing {
requires msg.service.api;
requires java.desktop;
provides msg.service.MsgService with msg.provider.swing.MsgServiceProvider;
}
Copying msg-lib.jar(the service API) to msg.service.provider.swing/lib, so that we can compile the provider classes:
D:\service-provider-method-example\msg.service.provider.swing>mkdir lib
D:\service-provider-method-example\msg.service.provider.swing>copy ..\msg.service.api\msg-service.jar lib\msg-service.jar 1 file(s) copied.
Compiling the classes:
D:\service-provider-method-example\msg.service.provider.swing>javac -d out --module-path lib src/module-info.java src/msg/provider/swing/MsgServiceProvider.java
Creating the jar:
D:\service-provider-method-example\msg.service.provider.swing>jar --create --file msg-service-swing.jar -C out .
The Service Client Application
my-app/src/com/logicbig/AppMain.javapackage com.logicbig;
import msg.service.MsgService;
import java.util.List;
public class AppMain {
public static void main(String[] args) {
List<MsgService> msgServices = MsgService.getInstances();
for (MsgService msgService : msgServices) {
msgService.showMessage("A test message");
}
}
}
my-app/src/module-info.javamodule my.app {
requires msg.service.api;
}
Copying msg-lib.jar (Service API) to my-app/lib/msg-lib.jar
D:\service-provider-method-example\my-app>mkdir lib
D:\service-provider-method-example\my-app>copy ..\msg.service.api\msg-service.jar lib\msg-service.jar 1 file(s) copied.
Copying msg-service-swing.jar (the provider) to my-app/lib/msg-service-swing.jar:
D:\service-provider-method-example\my-app>copy ..\msg.service.provider.swing\msg-service-swing.jar lib\msg-service-swing.jar 1 file(s) copied.
D:\service-provider-method-example\my-app>"tree /A /F" +---lib | msg-service-swing.jar | msg-service.jar | \---src | module-info.java | \---com \---logicbig AppMain.java
Compiling the classes:
D:\service-provider-method-example\my-app>javac -d out --module-path lib src/module-info.java src/com/logicbig/AppMain.java
Running the application
D:\service-provider-method-example\my-app>java --module-path out;lib --module my.app/com.logicbig.AppMain
Example ProjectDependencies and Technologies Used: |