Kick-Off Java 9 (Project Jigsaw & ServiceLoader) Part – II


Java  comes with major changes and new surprises for developers. Major changes came in  Java 5 and Java 8, but now Java 9 will come with new mysteries and changes. In the last post we were discussing about Java 9 with Jigsaw and in another post we were using ServiceLoader in Java instead of dependencies injections.

Java 9 gives us a clean way for using ServiceLoader in Java for maintain DI in application using modularization.  For detail, please visit our previous posts as mentioned above. Today we are creating Greetings example using Jigsaw and ServiceLoader. Below is our directory structure of sample application.

jigsaw

In this sample application, we will introduce two new packages com.knoldus.service and com.knoldus.service.provider.

Below is the conceptual diagram of how service loader works.

java-serviceloader

This works same as how DI frameworks work. Below are the step and code of our sample application.

Step I:

Decide the modules in our application and define abstract layer of modules. Like in the above example, i have one service module which contains an abstract service layer for greetings. Below is our code:


package com.knoldus.service;

public interface GreetingsService {
 void sayHello(String name);
}

Our module-info.java code as below:


module com.knoldus.service {
 exports com.knoldus.service;
}

This module is same as other module and we will just export our services from module. But the implementation of module is not here. For implementation of our abstract layer, we will create another module.

Step II

Like in our previous step, we created an abstract layer module, but still didn’t implement our abstract layer. For implementation, we need to create another module, which provide the implementation and map the abstract service with its implementation and exports.

In our example we are creating com.knoldus.service.provider service provider module for define the implementation and mapping as below:


package com.knoldus.service.impl;

import com.knoldus.service.GreetingsService;

public class ConsoleGreetings implements GreetingsService {

 @Override
 public void sayHello(String name) {
  System.out.println("Hello to "+name);
 }
}

our module-info.java as below:


module com.knoldus.service.provider {
 requires com.knoldus.service;

 provides com.knoldus.service.GreetingsService
  with com.knoldus.service.impl.ConsoleGreetings;
}

The tricky part is in module-info.java file. That file requires the service module with its implementation or provide the implementation of abstract layer using provides . This bindings is similar to Google Guice.

If we need to change the implementation, there is no need to change our Java code, our Java code is same, just change the module-info.java. The benefits of this approach is that, we will also migrate our old Java code into modular way, without any side effects.

Step III:

Another tricky part is in the consumer, which will consume the service. The information of the module is put in module-info.java file as below:


module com.knoldus.main {
 requires com.knoldus.util;
 requires com.knoldus.service;

 uses com.knoldus.service.GreetingsService;
}

In the above code, this consumer required util and service module, but still we are not defining requires for our provider module. Because, internally the implementation is manage by ServiceLoader. Whenever consumer will lookup for GreetingsService implementation, the ServiceLoader return the implementation, which is defined in our provider module.

How the ServiceLoader knows about implementation? In this module-info.java we need to define, our lookup declaration by using uses com.knoldus.service.GreetingsService. The ServiceLoader detects only those implementations which is defined using provides clause in provider module. If we are not defining the provider GreetingsService, it will throw an exception java.util.NoSuchElementException. Our lookup code is below in our consumer module:


package com.knoldus.providers;

import com.knoldus.service.GreetingsService;

import java.util.NoSuchElementException;
import java.util.ServiceLoader;

public class GreetingsProvider {

 private static GreetingsProvider provider;
 private ServiceLoader<GreetingsService> loader;

 private GreetingsProvider() {
  loader = ServiceLoader.load(GreetingsService.class);
 }

 public static GreetingsProvider getInstance() {
  if(provider == null) {
   provider = new GreetingsProvider();
  }
 return provider;
 }

 public GreetingsService serviceImpl() {
  GreetingsService service = loader.iterator().next();
  if(service != null){
   return service;
  }else {
   throw new NoSuchElementException("No implementation for GreetingsProvider");
  }
 }
}

For whole code, please download from github.

References:


KNOLDUS-advt-sticker

This entry was posted in Java, Scala and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s