1. Overview
jlink is a tool that generates a custom Java runtime image that contains only the platform modules that are required for a given application.
Such a runtime image acts exactly like the JRE but contains only the modules we picked and the dependencies they need to function. The concept of modular runtime images was introduced in JEP 220.
In this tutorial, we’ll learn how to create a custom JRE using jlink, and we’ll also run and test that our module functions correctly inside our JRE.
2. Need to Create a Custom JRE
Let’s understand the motivation behind custom runtime images with an example.
We’ll create a simple modular application. To know more about creating modular applications, please refer to our article on modularity.
First, let’s create a HelloWorld class and a corresponding module:
public class HelloWorld { private static final Logger LOG = Logger.getLogger(HelloWorld.class.getName()); public static void main(String[] args) { LOG.info("Hello World!"); } }
module jlinkModule { requires java.logging; }
To run this program, we only need HelloWorld, String, Logger, and Object classes.
Even though this program needs only four classes to run, all the predefined classes in the JRE also get executed, even if our program doesn’t require them.
Therefore, to run a small program, we have to maintain a complete JRE, which is simply a waste of memory.
So, a customized JRE is the best option to run our example.
With jlink, we can create our own, small JRE that contains only the relevant classes that we want to use, without wasting memory, and as a result, we’ll see increased performance.
3. Building Custom Java Runtime Images
We’ll perform a series of simple steps to create custom JRE images.
3.1. Compiling a Module
First, let’s compile the program mentioned above from the command line:
javac -d out src\main\java\module-info.java
javac -d out --module-path out src\main\java\com\baeldung\jlink\HelloWorld.java
Now, let’s run the program:
java --module-path out --module com.baeldung.jlink/com.baeldung.jlink.HelloWorld
The output will be:
Mar 13, 2019 10:15:40 AM com.baeldung.jlink.HelloWorld main INFO: Hello World!
3.2. Using jdeps to List the Dependent Modules
In order to use jlink, we need to know the list of the JDK modules that the application uses and that we should include in our custom JRE.
Let’s use the jdeps command to get the dependent modules used in the application:
jdeps --module-path out -s --module com.baeldung.jlink
The output will be:
com.baeldung.jlink -> java.base com.baeldung.jlink -> java.logging
This makes sense, as java.base is the minimum module needed for Java code libraries, and java.logging is used by a logger in our program.
3.3. Creating a Custom JRE with jlink
To create a custom JRE for a module-based application, we can use the jlink command. Here’s its basic syntax:
jlink [options] –module-path modulepath –add-modules module [, module…] --output <target-directory>
Now, let’s create a custom JRE for our program using Java 11:
jlink --module-path "%JAVA_HOME%\jmods";out --add-modules com.baeldung.jlink --output customjre
Here, the value after the –add-modules parameter tells jlink which module to include in the JRE.
Finally, the customjre next to the –output parameter defines the target directory where our custom JRE should be generated.
3.4. Running an Application with the Generated Image
Now, we have our custom JRE created by jlink.
To test our JRE, let’s try to run our module by navigating inside the bin folder of our customjre directory and run the command below:
java --module com.baeldung.jlink/com.baeldung.jlink.HelloWorld
4. Creating Custom JRE with Launcher Scripts
Optionally, we can also create a custom JRE with executable launcher scripts.
For this, we need to run the jlink command that has an extra –launcher parameter to create our launcher with our module and main class:
jlink --launcher customjrelauncher = jlinkModule/com.baeldung.jlink.HelloWorld --module-path "%JAVA_HOME%\jmods";out --add-modules jlinkModule --output customjre
This will generate two scripts: customjrelauncher.bat and customjrelauncher inside our customjre/bin directory.
Let’s run the script:
customjrelauncher.bat
And the output will be:
Mar 18, 2019 12:34:21 AM com.baeldung.jlink.HelloWorld main INFO: Hello World!
5. Conclusion
In this tutorial, we have learned how we can create a custom, modular JRE with jlink that only contains the bare minimum files needed for our module. We also looked into how to create a custom JRE with launcher scripts that can be easily executed and shipped.
Custom, modular Java runtime images are powerful. The goals for creating custom JREs are clear: they save on memory, improve performance, and also enhance security and maintainability. Lightweight custom JREs also enable us to create scalable applications for small devices.
The code snippets used in this tutorial are available over Github.