The jlink command

The jlink command needs the following inputs:

  • The module path: This is where it needs to look for modules. This is the directory (or directories) where the compiled modules are available.
  • The starting module: This is the module from which to begin the module resolution process. This could be one or many, separated by delimiters.
  • The output directory: This is the location where it stores the generated image.

The usage looks something like this, with the command broken into separate lines for readability:

jlink --module-path <module-path-locations> 
      --add-modules <starting-module-name> 
      --output <output_location>  

To run this command on our sample codebase and generate an image for the address book UI module, we first need to compile the modules in the same way that we usually do:

$ javac --module-source-path src -d out $(find . -name '*.java')  

Here, out is the location of the compiled modules, and thus, that is the module path for jlink. The module that serves as the starting point is packt.addressbook.ui.

In the same directory that we ran the javac command, we can now run jlink. To run the command, either make sure the  $JAVA_HOME/bin directory is in your operating system's  path, or use the path to access jlink directly:

$ $JAVA_HOME/bin/jlink --module-path out 
--add-modules packt.addressbook.ui --output image

Note that we get an error:

Error: Module java.base not found, required by packt.addressbook.ui 

We are missing the platform modules! Note that java.base is a core platform module and is not available in the module path we've specified in the preceding command. Platform modules don't get special treatment; their module location needs to be explicitly specified to the jlink command!

We've already seen that the core Java modules are available in $JAVA_HOME/jmods. Let's add that to the --module-path parameter. As before, in order to specify multiple paths there, we need to separate the paths with the : symbol (; on Windows operating systems):

$ $JAVA_HOME/bin/jlink --module-path $JAVA_HOME/jmods:out 
--add-modules packt.addressbook.ui --output image

jlink will now get to work and quietly generate the runtime image for us. Let's look at the structure of the image generated:

This should look familiar now. The structure is very similar to the JDK file structure we've already seen. One notable exception is that the jmods folder isn't here. This makes sense because this is a runtime image, and the jmods format is not designed to be used for runtime. Since this image contains only the modules necessary, they are all bundled into a common modules file in the lib folder.

Now that the image contains the runtime and the compiled application modules, it is a self-sufficient bundle. You can deploy this image on a computer that does not have the Java runtime installed and execute it without any problems.

Now, to execute our module from the runtime image, we need to execute the java executable that's available in the bin directory of the image, not the one in $PATH. You also don't have to specify the --module-path this time because the module resolution is already done! The generated image is already bundled with every module it needs, and thus already knows where to find them:

$ cd image/ 
$ bin/java -m packt.addressbook.ui/packt.addressbook.ui.Main 

You should see the address book UI application pop up. That's great, but you can probably tell something isn't right:

The names aren't sorted. Can you guess why? It's because the sorting modules haven't been bundled in! If you run the java --list-modules on the java executable in the image, you can see all the modules that have been bundled in. Note that the sorting service modules aren't included:

$ bin/java --list-modules 
java.base@9
 ... 
packt.addressbook.lib 
packt.addressbook.ui 
packt.contact 
packt.sortutil 

Remember that the module resolution process traverses the module graph and adds modules that have a direct dependency using the requires clause. Services, by definition, are loosely coupled and so are not required by any module. Because of this reason, both the service modules--packt.sort.bubblesort and packt.sort.javasort--haven't been included. This behavior of jlink is intentional. The bundling of service modules needs to be explicitly stated to the command.

Note that the java --list-modules command displays the observable modules that are available in the runtime image on which the command is run. All along, we've run the command on the installed JDK, so it listed all (and only) the platform modules. This time, we have run the command on the generated runtime image, which is a combination of our application modules and a select few platform modules. Thus, the output of the command reflects that accordingly.

There are a couple of ways we can fix our problem. The first way is to add the service modules to the list of starting-point modules for module resolution using the --add-modules option. Multiple module names can be specified for this option, with the names separated by commas. These modules and their dependencies will then also get bundled into the image, since the module resolution process will run starting from each of those modules, too, and add them to the resolved set:

$ $JAVA_HOME/bin/jlink --module-path $JAVA_HOME/jmods:out 
--add-modules packt.addressbook.ui,packt.sort.bubblesort,packt.sort.javasort
--o
utput image

Now, running java --list-modules in the generated image should show the sorting modules. Also, when executing the application, the UI should now show the list of contacts sorted by last name:

$ bin/java --list-modules
  java.base@9-ea
  ...
  packt.addressbook.lib
  packt.addressbook.ui
  packt.contact
  packt.sort.bubblesort
  packt.sort.javasort
  packt.sortutil

Another alternative to bundling in services is to use the --bind-services option of jlink:

$ $JAVA_HOME/bin/jlink --module-path $JAVA_HOME/jmods:out 
--add-modules packt.addressbook.ui --bind-services --output image

This parameter automatically identifies any services consumed by modules when it checks each module through the module resolution process. Then, all observable modules that declare that they are providers for those services will be automatically bundled in. This is an easier option because you don't have to explicitly mention service modules yourself, but there's a chance that you might pull in more modules than you really require. Let's say there's some random module in the module path that your application doesn't use, but it just happens to implement one of the service types you've used. Well, that module gets pulled in with this option!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.38.176