java模块——使用 47M 的java环境运行HelloWorld
前言
我们知道,运行java程序需要jre或jdk环境,但是现在的jdk安装包已经很大了,如果我们的程序很简单,并且需要把程序发送给其他没有jdk环境的人的运行要如何做呢?如何精简我们的程序包呢?
从java9开始的模块功能为我们提供了解决方案。Java 库设计者现在可以将代码清晰地划分为模块,这些模块以编程的方式指定它们所依赖的每个模块,并定义导出哪些组件以及哪些组件完全不可用。
简单命令
列出java中的模块
java --list-modules
你可能会看到类似下面的打印结果
java.base@21.0.2
java.compiler@21.0.2
java.datatransfer@21.0.2
java.desktop@21.0.2
java.instrument@21.0.2
java.logging@21.0.2
java.management@21.0.2
java.management.rmi@21.0.2
java.naming@21.0.2
java.net.http@21.0.2
java.prefs@21.0.2
java.rmi@21.0.2
java.scripting@21.0.2
java.se@21.0.2
java.security.jgss@21.0.2
java.security.sasl@21.0.2
java.smartcardio@21.0.2
java.sql@21.0.2
java.sql.rowset@21.0.2
java.transaction.xa@21.0.2
java.xml@21.0.2
java.xml.crypto@21.0.2
jdk.accessibility@21.0.2
jdk.attach@21.0.2
jdk.charsets@21.0.2
jdk.compiler@21.0.2
jdk.crypto.cryptoki@21.0.2
jdk.crypto.ec@21.0.2
jdk.crypto.mscapi@21.0.2
jdk.dynalink@21.0.2
jdk.editpad@21.0.2
jdk.hotspot.agent@21.0.2
jdk.httpserver@21.0.2
jdk.incubator.vector@21.0.2
jdk.internal.ed@21.0.2
jdk.internal.jvmstat@21.0.2
jdk.internal.le@21.0.2
jdk.internal.opt@21.0.2
jdk.internal.vm.ci@21.0.2
jdk.internal.vm.compiler@21.0.2
jdk.internal.vm.compiler.management@21.0.2
jdk.jartool@21.0.2
jdk.javadoc@21.0.2
jdk.jcmd@21.0.2
jdk.jconsole@21.0.2
jdk.jdeps@21.0.2
jdk.jdi@21.0.2
jdk.jdwp.agent@21.0.2
jdk.jfr@21.0.2
jdk.jlink@21.0.2
jdk.jpackage@21.0.2
jdk.jshell@21.0.2
jdk.jsobject@21.0.2
jdk.jstatd@21.0.2
jdk.localedata@21.0.2
jdk.management@21.0.2
jdk.management.agent@21.0.2
jdk.management.jfr@21.0.2
jdk.naming.dns@21.0.2
jdk.naming.rmi@21.0.2
jdk.net@21.0.2
jdk.nio.mapmode@21.0.2
jdk.random@21.0.2
jdk.sctp@21.0.2
jdk.security.auth@21.0.2
jdk.security.jgss@21.0.2
jdk.unsupported@21.0.2
jdk.unsupported.desktop@21.0.2
jdk.xml.dom@21.0.2
jdk.zipfs@21.0.2
查看模块的内容
java --describe-module java.base
PS C:\Users\zjw> java --describe-module java.base
java.base@21.0.2
exports java.io
exports java.lang
exports java.lang.annotation
exports java.lang.constant
exports java.lang.foreign
exports java.lang.invoke
exports java.lang.module
exports java.lang.ref
exports java.lang.reflect
exports java.lang.runtime
exports java.math
exports java.net
exports java.net.spi
exports java.nio
exports java.nio.channels
exports java.nio.channels.spi
exports java.nio.charset
exports java.nio.charset.spi
exports java.nio.file
...
可以看到java中包含了很多的模块。下面我们利用java.base模块创建我们的程序,并在程序中打印一句HelloWorld
。
创建项目
创建一个maven项目,结构如下
helloworld-module
│ └─pom.xml
│
└─src
└─main
└─java
└─module-info.java
│
└─com
└─zjw
└─helloworld
└─HelloWorld.java
HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
module-info.java
module helloworld.module {
requires java.base;
exports com.zjw.helloworld;
}
接着编译好项目,并运行下面的命令来创建自定义的 Java 运行时映像:
jlink --module-path E:\SDK\Java\temurin\jdk-21.0.2+13\jmods;target/classes --add-modules helloworld.module --output helloworld
这是会在项目下生成一个helloworld的文件,里面就是我们的自定义java运行环境。
我们在里面创建一个run.bat文件,这样可以方便执行我们的helloworld模块。
@echo off
set DIR=%~dp0
"%DIR%bin\java" -m helloworld.module/com.zjw.helloworld.HelloWorld
echo.
echo Press any key to continue...
pause >nul
运行run.bat
可以看到我们的程序正确执行了,这样我们可以把程序发给我们的小伙伴去运行了。
对比完整的java
可以看到新打包的java和完整的java大小对比,只有47M便可运行java程序,这是很大的精简。
---------------
我每一次回头,都感觉自己不够努力,所以我不再回头。
---------------