Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jlink: service binding links many unnecessary modules

I face the problem that the service binding option of jlink links many, many modules, none of them seems to be necessary. These modules aren't linked when the service binding option is omitted.

Questions:

  • Q1: Do you see the same behavoir in your environment ?
  • Q2: Is this a bug or a desired behavoir ?
  • Q3: Why all these modules are linked ?

My application: The application is a simple service consisting of an interface, a provider and a consumer, each packed into a separate module, called modService, modProvider, modConsumer (details below).

OS: Windows 10

Jlink without --bind-services yields the expected result:

jlink --module-path "mods;%JAVA_HOME%\jmods"
    --add-modules modConsumer
    --output myRuntime

java --list-modules
java.base@9
modConsumer
modService 

When the --bind-services option is applied, I would expect that in addition the module modProvider should be linked. However, see what happens (the three custom modules are at the end):

jlink --module-path "mods;%JAVA_HOME%\jmods"
    --bind-services
    --add-modules modConsumer
    --output myRuntime

java --list-modules
java.base@9
java.compiler@9
java.datatransfer@9
java.desktop@9
java.logging@9
java.management@9
java.management.rmi@9
java.naming@9
java.prefs@9
java.rmi@9
java.scripting@9
java.security.jgss@9
java.security.sasl@9
java.smartcardio@9
java.xml@9
java.xml.crypto@9
jdk.accessibility@9
jdk.charsets@9
jdk.compiler@9
jdk.crypto.cryptoki@9
jdk.crypto.ec@9
jdk.crypto.mscapi@9
jdk.deploy@9
jdk.dynalink@9
jdk.internal.opt@9
jdk.jartool@9
jdk.javadoc@9
jdk.jdeps@9
jdk.jfr@9
jdk.jlink@9
jdk.localedata@9
jdk.management@9
jdk.management.cmm@9
jdk.management.jfr@9
jdk.naming.dns@9
jdk.naming.rmi@9
jdk.scripting.nashorn@9
jdk.security.auth@9
jdk.security.jgss@9
jdk.unsupported@9
jdk.zipfs@9
modConsumer
modProvider
modService

I have no clue why all these modules are linked because the provider just returns a string so that no other jdk module than java.base should be needed.

Below are the Java artifacts:

package test.service; 

public interface HelloService { 
  public String sayHello(); 
}

package test.provider; 
import test.service; 

public class HelloProvider implements HelloService { 
  @Override public String sayHello() { return "Hello!"; }
}

package test.consumer; 
import test.service; 
import java.util.ServiceLoader; 

public class HelloConsumer { 
  public static void main(String... args) { 
    ServiceLoader.load(HelloService.class).forEach(s -> System.out.println(s.sayHello())); 
  }
}

module modService { 
  exports test.service; 
}

module modProvider { 
  requires modService; 
  provides test.service.HelloService with test.provider.HelloProvider; 
}

module modConsumer { 
  requires modService; 
  uses test.service.HelloService; 
} 

Any help is appreciated.

like image 281
user120513 Avatar asked Jan 26 '18 19:01

user120513


2 Answers

Short version

  • Q1: Yes.
  • Q2: Desired behavior
  • Q3: Because you told jlink so with --bind-services 😉

Long Version

By default jlink does not bind services, to keep the created runtime as small as possible. That changes with --bind-services, about which the documentation says

Link service provider modules and their dependencies.

That mirrors the behavior during regular module resolution where, after all dependencies have been resolved, all modules that provide a service used by those modules are included in the readability graph.

The same happens in your case, so all modules providing services used by java.base, modConsumer, and modService are included in the image. As you have found out, that are quite a lot.

Solution

If you want to avoid that, you have to forego --bind-services and instead explicitly list the providers that you want to see in your image:

jlink --module-path "mods;%JAVA_HOME%\jmods"
    --add-modules modConsumer,modProvider
    --output myRuntime
like image 165
Nicolai Parlog Avatar answered Sep 27 '22 21:09

Nicolai Parlog


As stated in the jlink documentation. The

--bind-services 

Link service provider modules and their dependencies.

further, a sample in the same illustrates that the

option will link the modules resolved from root modules with service binding; see the Configuration.resolveAndBind method.

From your previous command the root module and the ones resolved in your module graph by default are :

java.base@9
modConsumer
modService

and further, the other modules listed while making use of --bind-services flag are resolved via the java.base module.

I would expect that in addition the module modProvider should be linked

As suggested by nicolai, you can add the provider module and ensure that it is resolved as well in the module graph.

 --add-modules modConsumer,modProvider

Thinking out loud. 1. The current process for finding providers is iterative. 2. Is it possible to specify modules for which one to look for while finding service providers explicitly?

like image 44
Naman Avatar answered Sep 27 '22 22:09

Naman