How to create a custom JRE using Java Modules?

Starting Java 9 , Java introduced Modules.

It allowed us to organize our code into modules. Also Java organised its own internal libraries into modules.

Here is the list of modules in Java by default(you can get this by running the command : java –list-modules from command prompt starting Java 9):

G:\softwares\java14\jdk-14\bin>java --list-modules
java.base@14
java.compiler@14
java.datatransfer@14
java.desktop@14
java.instrument@14
java.logging@14
java.management@14
java.management.rmi@14
java.naming@14
java.net.http@14
java.prefs@14
java.rmi@14
java.scripting@14
java.se@14
java.security.jgss@14
java.security.sasl@14
java.smartcardio@14
java.sql@14
java.sql.rowset@14
java.transaction.xa@14
java.xml@14
java.xml.crypto@14
jdk.accessibility@14
jdk.aot@14
jdk.attach@14
jdk.charsets@14
jdk.compiler@14
jdk.crypto.cryptoki@14
jdk.crypto.ec@14
jdk.crypto.mscapi@14
jdk.dynalink@14
jdk.editpad@14
jdk.hotspot.agent@14
jdk.httpserver@14
jdk.incubator.foreign@14
jdk.incubator.jpackage@14
jdk.internal.ed@14
jdk.internal.jvmstat@14
jdk.internal.le@14
jdk.internal.opt@14
jdk.internal.vm.ci@14
jdk.internal.vm.compiler@14
jdk.internal.vm.compiler.management@14
jdk.jartool@14
jdk.javadoc@14
jdk.jcmd@14
jdk.jconsole@14
jdk.jdeps@14
jdk.jdi@14
jdk.jdwp.agent@14
jdk.jfr@14
jdk.jlink@14
jdk.jshell@14
jdk.jsobject@14
jdk.jstatd@14
jdk.localedata@14
jdk.management@14
jdk.management.agent@14
jdk.management.jfr@14
jdk.naming.dns@14
jdk.naming.rmi@14
jdk.net@14
jdk.nio.mapmode@14
jdk.rmic@14
jdk.scripting.nashorn@14
jdk.scripting.nashorn.shell@14
jdk.sctp@14
jdk.security.auth@14
jdk.security.jgss@14
jdk.unsupported@14
jdk.unsupported.desktop@14
jdk.xml.dom@14
jdk.zipfs@14

Our java applications doesn’t always need all these modules to be run.

More about modules on another post.

In this post we will see how modules help in creating custom JRE.

But why a custom JRE?

Imagine you are building a custom image to deploy into a container (Eg ) Docker image ).

You need a base image to build your custom image. Most often for a java application the base image contains a JRE packaged inside it.

As seen above , a JRE contains many modules and not all modules are required for our application. Using only those modules that are required for our application will reduce the image size to a great extent. That will save memory!

Now let’s create a custom JRE.

I have created a simple java application which prints “Hello World” onto the console. I have written this in Java 14 . I have created a module ‘customjre’ along with a single Java class which prints the Hello World message.

Here is the structure:

Here is the Java class:

package customjre;

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

}

Here is the module:

module customjre {
}

There are no dependencies listed in the module as I am just printing to the console . This is handled by java.base module which is added to every module by default.

Below are the steps to create the custom image:

STEP 1: Compile both the classes and module:

(I used the version of java in my G:\softwares\java14\jdk-14\bin path as it contained the latest version )

C:\Users\Vijay\eclipse-workspace-new\customjre>G:\softwares\java14\jdk-14\bin\javac -d out src\module-info.java
C:\Users\Vijay\eclipse-workspace-new\customjre>G:\softwares\java14\jdk-14\bin\javac -d out --module-path out src\customjre\HelloWorld.java

We need to compile the module first using javac command (-d stands for destination which is ‘out’ folder above)

And then the class with the module path specified as shown above in the second line

The compiled classes are generated in out folder:

STEP 2: Run the application and verify.

We can verify if the compilation was proper by running the java command:

C:\Users\Vijay\eclipse-workspace-new\customjre>G:\softwares\java14\jdk-14\bin\java --module-path out --module customjre/customjre.HelloWorld
Hello World

Hello World got printed!

A simple Java program run using the default JRE provided by Java.

Let’s create the custom JRE now and run our class using it..

Java provides a command line tool named ‘jlink’ which can be used to create a custom image.

STEP 3: Run jlink command

Here is the syntax for jlink command :

jlink --module-path <module-path> --add-modules <comma-separated-module-names> --output <target-directory>

Here is the command :

C:\Users\Vijay\eclipse-workspace-new\customjre>G:\softwares\java14\jdk-14\bin\jlink --module-path out --add-modules customjre --output build

That’s it!

A new JRE got created under a folder named build.

Let me go inside the bin directory of the new JRE and list all the modules in it:

C:\Users\Vijay\eclipse-workspace-new\customjre\build\bin>java --list-modules
customjre
java.base@14

Just two modules , compared to the 70+ modules that are shipped in the default JDK as shown in the begining of the post.

Let’s compare the size of the default JDK and the JRE we just built:

Default JDK:

Around 307 MB.

Let’s look at the custom JRE size:

Around 39 MB.

Almost 8 times smaller!.

That saves a lot of space!

Let’s run our Hello World class using this JRE:

C:\Users\Vijay\eclipse-workspace-new\customjre\build\bin>java --module-path out --module customjre/customjre.HelloWorld
Hello World

Notice the path where the java command is executed. It is the path of the new JRE created.And Hello World is printed using the custom JRE.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s