Before Java 9 and Project Jigsaw, you would have to package the entire monolithic Java Runtime Environment (JRE) to distribute your application with an embedded JRE runtime. This took up a lot of space. Now, you can generate your own custom runtime with only the modules you want to keep the size of the final package smaller.
You can think of a runtime image as another name for a Java runtime environment (JRE). When you create a custom runtime, you are generating a new JRE that only includes the modules you want. You can exclude core java modules that you don't need and you can include custom modules that you wrote. They will all be "baked in" to the runtime.
If you are familiar with Python Virtual Environments, it is similar to that. It is a directory that contains an isolated Java environment with only the specific dependencies needed that will not conflict with other isolated runtimes.
After following this guide, you will understand how to use
jlink to create runtime images with only the modules you want. You should also know how to add custom modules including third-party modules like JavaFX.
Simplest jlink example
To get a basic understanding of what
jlink does, try running these basic commands.
This first example will create a runtime image with only the most basic modules for the core language.
# Create a runtime image with minimal modules jlink --output my-minimal-runtime --add-modules java.base
It generates a directory named
minimal-runtime/ that will contain a few subdirectories:
bin/- All the necessary dynamic libraries, java executable, and other requirements
conf/- Configuration files
include/- Header files
legal/- License files
release- Contains info about the Java version
These runtime images are system-specific. For example, in Windows, the
bin/ directory contains
java.exe which will only work on Windows. You can use these runtime images packaged with your application to distribute the smallest package possible.
See what modules a runtime includes
You can see what modules a Java runtime includes by running the
java command with the
--list-modules option. For example, if you followed the previous step and created
my-minimal-runtime/ then you could run:
Choose which modules to include
This example shows how to include multiple modules. In this case, the
# Create an image with just base and logging modules jlink --output minimal-with-logging --add-modules java.base,java.logging
This example would create a runtime image that contained all the modules in Java SE. This might be convenient but could also have unnecessary dependencies.
# Create a runtime image with all Java SE modules jlink --output my-custom-jdk-runtime --add-modules java.se
To see a visual representation of how modules depend on each other, check out this blog post on TechTalks | Java 9 : Future 3.
Add custom modules
To add any custom modules that you created, just make sure you have the classes or the jar files necessary in the
--module-path option and the module name is listed in the
--add-modules option. For example:
# Multiple modules are separate by comma # Multiple module paths are separated by semi-colon jlink --output myapp --add-modules mymod1,mymod2 --module-path .;target/my.jar
Run a module using the custom runtime
Once you have the runtime built with the modules included, you can run any module using the java executable. This assumes you did not use the
--strip-native-commands option which would remove the
This example would run a class from a module in the runtime.
myruntime/bin/java --module mymodule/com.devdungeon.MainWindow
To run a JAR that is not already packed in to the runtime, add the JAR to the module path and then specify the module as normal. If the JAR has a main class defined in the manifest, you can run it directly.
# Run a module from a JAR using a custom runtime myruntime/bin/java --module-path .;mylib.jar --module mymodule/MyClass # Or if the JAR has a main class defined in the JAR manifest myruntime/bin/java -jar mylib.jar
Remember, if you need to check what modules a runtime has you can use
See what modules a JAR depends on
If you want to see what modules a JAR depends on so you know what modules to include in the runtime, you can use the
jdeps tool like this:
Building a runtime for Swing
If you want to make Swing GUI application you will need to depend on the
# Create a runtime image with required components # to use Swing desktop GUI jlink --output jdk-with-swing --add-modules java.desktop
Building a runtime for Java FX
In order to build with JavaFX you need to take some extra steps.
- You need to download the JavaFX modules from https://gluonhq.com/products/javafx/ (e.g.
- When running
jlinkyou need to tell it where to find the modules you extracted with the
- You need to tell
jlinkto include the modules with
jlink --output jdk-with-fx --module-path C:\opt\javafx-jmods-13.0.1 --add-modules javafx.media,javafx.web,javafx.fxml,java.logging
Generate native launch scripts
You can specify a native launcher by adding the
--launcher option along with the module/class name to use as the main class. For example:
jlink --output myapp --module-path mylib.jar --add-modules mymodule --launcher mylauncher=mymodule/com.devdungeon.MainWindow
This will create a launcher named
mylauncher.bat) using the module/class specified. The module name in
--add-modules and in the launcher must match the module name in your
module-info.java file. The launcher format is like this:
jlink --output myapp --add-modules Mavenproject4 --launcher myLauncher=mymodule/com.devdungeon.mavenproject4.MainWindow --module-path target\mavenproject4-1.0-SNAPSHOT.jar
You can then run your class by simply running the native launcher (Windows example):
You can also create multiple launcher scripts for different classes by adding multiple
Strip out even more stuff
There are a few options that might help reduce file sizes even more:
--strip-debug --strip-native-commands --compress 2 --no-header-files --no-man-pages
Package native installers with jpackage
jlink alone, you have a package that you could distribute with native launchers. From here, you could use a tool like InnoSetup to create an MSI installer or build your or .deb package, but in Java 14+, the new
jpackage comes out-of-the box. The
jpackage tool generates distributable packages for native systems including:
.rpmpackages for Debian and RedHat based distros
jpackage will run
jlink and generate a runtime image, or you can bring your own image that you created yourself with
To learn more about how easy the
jpackage tool is check out this great talk on YouTube Java Packaging Tool: Create Native Packages to Deploy Java Applications by Kevin Rushforth.
After following this guide, you should understand how to use
jlink to create simple runtime images with only the modules you want. You should also know how to add multiple modules including third-party modules like JavaFX.