You are currently viewing Going Beyond Java 8: Create Custom Java Runtimes with jlink

Going Beyond Java 8: Create Custom Java Runtimes with jlink

According to some surveys such as that of JetBrains, version 8 of Java is currently the most used by developers all over the world, despite being a 2014 release. What you are reading is one in a series of articles titled “Going beyond Java 8”, inspired by the contents of my book “Java for Aliens”. These articles will guide the reader step by step to explore the most important features introduced starting from version 9. The aim is to make the reader aware of how important it is to move forward from Java 8, explaining the enormous advantages that the latest versions of the language offer.

Before Java 9, to run a Java application on any platform it was necessary that the Java Runtime Environment was installed on it. Today the classic JRE no longer exists, and it is not automatically installed when we install the JDK as in the past. There is no longer the Java Plugin too, that was installed in browsers to allow the execution of applications that used the historical Applet and Java Web Start technologies (no longer available). Today, to allow the execution of a Java application on a particular platform, we can create a custom Java runtime that contains only the libraries that the program needs to run, and distribute it as part of the application itself. To do this, just use the tool introduced with the JDK 9 called jlink, which takes advantage of the JDK modularization.

 

JDK Modularization

With the introduction of the module concept in version 9, a major refactoring of the JDK has been done. This means that now the packages of the standard Java library are organized within modules (that physically, are simple folders).

In particular, the JDK version 16 defines 68 modules, but this number will probably change (in version Java 9 there were 98). We can check this by running the command:

java --list-modules

which will print the list of all the modules present in the JDK that we report in the following table:

Figure 1 – JDK 16 Modules.

For example, the java.base module contains the fundamental (base) packages such as java.lang, java.io, java.math, java.time, java.util, java.util.stream and many others.

 

What we can do now

Before the modularization of the JDK, our programs had to take advantage of the complete installation of the Java Runtime Environment on the target platform. They therefore had all the JRE libraries available (such as javafx.*java.sql.*, Applet) even if they were not used. All these libraries were included in the rt.jar file.

With modules, on the other hand, it is possible to create customized runtimes. In fact, from Java 9 onwards, we can distribute our programs bringing with them only the necessary libraries. In this way, we can reduce the size of the application and improve its performance. Furthermore, it will not be necessary to install the JRE on the target machine, since we will create a customized and optimized Java runtime that we will distribute together with the application itself.

 

The jlink tool

Java 9 introduced a new tool called jlink, a very simple command-line tool to use. It allows us to create custom runtimes only with the modules that our application needs. For example, with the following command we will create a runtime containing only the java.base module:

jlink --add-modules java.base --output javabasert

In fact, with the --add-modules option we add the java.base module to the runtime, while with the --output option we give the name to the runtime (javabasert).

At this point jlink will create a runtime inside a folder called javabasert, with the entire structure consisting of folders bin, lib, include, conf, legal.

Figure 2 - The javabasert custom runtime structure, created with jlink

The size of the javabasert runtime we created does not exceed 40 megabytes, while the full JDK is approximately 290 megabytes in size. We can also fully compress our runtime using the --compress 2 option to get a size of about 27 megabytes.

With the following command:

javabasert\bin\java --list-modules

we can print the list of modules that the new runtime supports, obtaining the following output:

java.base@16

which confirms that with javabasert we can only exploit the libraries included in the java.base module of version 16.

If we wanted to run an application using the newly created runtime, considering the usual HelloWorld class:

public class HelloWorld {   
    public static void main(String args[])   {
        System.out.print("Hello World!");
    }
}

simply use a command like the following:

javabasert\bin\java HelloWorld

 

Transitive dependencies between modules

If we want to create a runtime that also includes the java.desktop module which contains the libraries to create graphical interfaces, we can run the command:

jlink --add-modules java.base,java.desktop --output javabasedeskrt

where we called the new custom runtime javabasedeskrt.

To check the correct definition of the environment, run the command:

javabasedeskrt\bin\java --list-modules

which will produce the following output:

java.base@16
java.datatransfer@16
java.desktop@16
java.prefs@16
java.xml@16

In practice, even if we thought we had only added two modules, in reality we also find others. This is because the modules are linked by dependency relationships. In particular, even if we asked jlink to add only the java.base and java.desktop to our runtime, the latter module has dependencies on java.prefs, java.xml, java.datatransfer and also with java.base. In fact, we could also have avoided specifying java.base between the modules to be included, we would have obtained the same result.

 

The jdeps tool

To understand how to create the right runtime, in JDK 9 the jdeps tool was revised to support modular dependencies. Also this tool is very simple to use. For example, considering the HelloWorld class, the following command:

jdeps HelloWorld.class

will produce the following output:

HelloWorld.class -> java.base
<unnamed>                 -> java.io                java.base
<unnamed>                 -> java.lang              java.base

which shows us the dependence of the HelloWorld class on the java.base module, and since our class does not belong to a package, it is clear that the anonymous package (unnamed) depends on the java.io and java.lang packages. Obviously, if the class belonged to the mypackage package, then we would see mypackage instead of the <unnamed> string.

The jdeps command can also take folders and JAR files as well as classes as input.

To view all the options available for use with both the jlink and jdeps tools, we can use the –help option.

 

Conclusion

Undoubtedly the jlink tool represents a step towards the future for Java. In fact, by providing very little information we can create customized runtimes for our applications, making them more performing, less bulky, and easier to distribute. The support of the jdeps tool allows us to understand which modules are needed in the runtime to be created for our applications. Furthermore, both tools are particularly easy to use.

 

Author Notes

Even ignoring the increased security offered by the latest versions of the JDK, there are plenty of reasons to upgrade your knowledge of Java, or at least your own Java runtime installations. My book “Java for Aliens“, which inspired the ” Going beyond Java 8″ series, contains all the information you need to learn Java from scratch, and uses a well-tested teaching method that has been perfected over 20 years of experience, which makes learning simple and exciting. It is also structured to deepen the topics and have superior knowledge that can make a difference in your career.

This article is mainly inspired by section 19.3 of chapter 196 of the book “Java for Aliens

For more information visit https://www.javaforaliens.com.

This Post Has 2 Comments

  1. Björn Kautler

    > Platform Dependence
    >
    > The jlink tool is platform-dependent. This means that if we want to deploy a Java application on various platforms, then we have to create custom runtimes on each of the platforms via jlink. It is not possible to create a custom runtime on a particular platform for a different platform. For example, we cannot create a Linux runtime using jlink on a Windows System.

    That’s not true, it works just fine.
    You just need both JDKs.
    The one for the system where you want to run jlink to run jlink
    and the one for the target platform to specify the JMOD files from.

    1. cdesio

      Hi Björn, thank you for the clarification. I preferred to delete that part, then I will calmly update the article.
      Thanks again
      Claudio

Leave a Reply