![]() | |
|
Java since version 6 supported service-provider loading facility via the java.util.ServiceLoader
class.
Using Service Loader you can have a service provider interface (SPI) simply called Service, and multiple implementations of the SPI simply
called Service Providers. These Service Providers in Java 8 and earlier are located in the classpath and loaded at
run time.
Since Java 9 you can develop Services and Service Providers as modules. A service module declares one or more interfaces whose
implementations will be provided at run time by some provider modules. A provider module declares what implementations of service interfaces it
provides
.The module that discovers and loads service providers must contain a uses
directive in its declaration.
Developing Service module
Let's say we have a service interface p1.GreeterIntf
:
package p1; public interface GreeterIntf { public abstract void greet(); }
Export the p1
package in module-info.java
:
module modS { exports p1; }
Compile:
C:\1Z0-817>javac service/module-info.java service/p1/GreeterIntf.java
C:\1Z0-817\SERVICE │ module-info.class │ module-info.java │ └───p1 GreeterIntf.class GreeterIntf.java
Package as JAR:
C:\1Z0-817>jar --create --file service.jar -C service .
Developing Service Provider module
Let's create service interface implementation:
package p2; import p1.GreeterIntf; public class GreeterImpl implements GreeterIntf { @Override public void greet() { System.out.println("Greeting from GreeterImpl !"); } }
A service provider will use "provides ... with ...
" directive to declare what service interface it intends to use (by using
provides
keyword) and what implementation of the interface it wants to expose (by using with
keyword).
module modP { requires modS; provides p1.GreeterIntf with p2.GreeterImpl; }
![]() | |
We don't have to specify the service implementation in a file under the resource directory |
Compile the code:
C:\1Z0-817>javac -p service.jar provider/module-info.java provider/p2/GreeterImpl.java
C:\1Z0-817\PROVIDER │ module-info.class │ module-info.java │ └───p2 GreeterImpl.class GreeterImpl.java
Create provider JAR:
C:\1Z0-817>jar --create --file provider.jar -C provider .
Developing Service client application
Create a Client class:
package app; import java.util.ServiceLoader; import p1.GreeterIntf; public class Client { public static void main(String[] args) { ServiceLoader<GreeterIntf> services = ServiceLoader.load(GreeterIntf.class); services.findFirst().ifPresent(s -> s.greet()); } }
In order for a service to be used, its providers need to be discovered and loaded. The ServiceLoader
class
does the work of discovering and loading the service providers. The module that discovers and loads service providers must
contain a uses <service interface name>
directive in its declaration.
If a module uses the ServiceLoader<GreeterIntf> class to load the instances
of service providers for a service interface named p1.GreeterIntf
, the module declaration must contain the
uses p1.GreeterIntf
declaration as follows:
module modC { requires modS; uses p1.GreeterIntf; }
Compile the client code:
C:\1Z0-817>javac -p service.jar service-client/module-info.java service-client/app/Client.java
C:\1Z0-817\SERVICE-CLIENT │ module-info.class │ module-info.java │ └───app Client.class Client.java
Run the client code:
C:\1Z0-817>java -p service.jar;provider.jar;service-client -m modC/app.Client Greeting from GreeterImpl !
![]() ![]() ![]() |