Chapter 2. Services in a Modular Application

2.1.  Describe the components of Services including directives

[Note]

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;
}
					

[Important]

We don't have to specify the service implementation in a file under the resource directory META-INF/services as of Java 9.

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 !					
					

Professional hosting         Exam 1Z0-817: Upgrade OCP Java 6, 7 & 8 to Java SE 11 Developer Quiz     Exam 1Z0-810: Upgrade to Java SE 8 Programmer Quiz