一、编写java文件
Greeting.java
package com.greeting;
public class Greeting {
public boolean hello(String xmlNsPrefix) {
return false;
}
}
Main.java
package com.main;
import com.greeting.Greeting;
import javax.xml.XMLConstants;
public class Main {
public static void main(String[] args) {
Greeting g = new Greeting();
System.out.println(g.hello(XMLConstants.XML_NS_PREFIX));
}
}
module-info.java
module hello.world {
requires java.base; // 可不写,任何模块都会自动引入java.base
requires java.xml;
}
三个java文件放在 /home/zxm/testjmod
下,再新建 foo1
目录,用于存放编译生成的 class
文件
目录结构:
foo1/
Greeting.java
Main.java
module-info.java
二、编译文件
java版本:
zxm@zxm-pc:~/testjmod$ java -version
java version "11.0.16.1" 2022-08-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.16.1+1-LTS-1)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.16.1+1-LTS-1, mixed mode)
java命令使用:
zxm@zxm-pc:~/testjmod$ java -help
用法:java [options] <主类> [args...]
(执行类)
或 java [options] -jar <jar 文件> [args...]
(执行 jar 文件)
或 java [options] -m <模块>[/<主类>] [args...]
java [options] --module <模块>[/<主类>] [args...]
(执行模块中的主类)
或 java [options] <源文件> [args]
(执行单个源文件程序)
将主类、源文件、-jar <jar 文件>、-m 或
--module <模块>/<主类> 后的参数作为参数
传递到主类。
其中,选项包括:
-cp <目录和 zip/jar 文件的类搜索路径>
-classpath <目录和 zip/jar 文件的类搜索路径>
--class-path <目录和 zip/jar 文件的类搜索路径>
使用 : 分隔的, 用于搜索类文件的目录, JAR 档案
和 ZIP 档案列表。
-p <模块路径>
--module-path <模块路径>...
用 : 分隔的目录列表, 每个目录
都是一个包含模块的目录。
--upgrade-module-path <模块路径>...
用 : 分隔的目录列表, 每个目录
都是一个包含模块的目录, 这些模块
用于替换运行时映像中的可升级模块
--add-modules <模块名称>[,<模块名称>...]
除了初始模块之外要解析的根模块。
<模块名称> 还可以为 ALL-DEFAULT, ALL-SYSTEM,
ALL-MODULE-PATH.
--list-modules
列出可观察模块并退出
-d <module name>
--describe-module <模块名称>
描述模块并退出
--dry-run 创建 VM 并加载主类, 但不执行 main 方法。
此 --dry-run 选项对于验证诸如
模块系统配置这样的命令行选项可能非常有用。
--validate-modules
验证所有模块并退出
--validate-modules 选项对于查找
模块路径中模块的冲突及其他错误可能非常有用。
-D<名称>=<值>
设置系统属性
-verbose:[class|module|gc|jni]
启用详细输出
-version 将产品版本输出到错误流并退出
--version 将产品版本输出到输出流并退出
-showversion 将产品版本输出到错误流并继续
--show-version
将产品版本输出到输出流并继续
--show-module-resolution
在启动过程中显示模块解析输出
-? -h -help
将此帮助消息输出到错误流
--help 将此帮助消息输出到输出流
-X 将额外选项的帮助输出到错误流
--help-extra 将额外选项的帮助输出到输出流
-ea[:<程序包名称>...|:<类名>]
-enableassertions[:<程序包名称>...|:<类名>]
按指定的粒度启用断言
-da[:<程序包名称>...|:<类名>]
-disableassertions[:<程序包名称>...|:<类名>]
按指定的粒度禁用断言
-esa | -enablesystemassertions
启用系统断言
-dsa | -disablesystemassertions
禁用系统断言
-agentlib:<库名>[=<选项>]
加载本机代理库 <库名>, 例如 -agentlib:jdwp
另请参阅 -agentlib:jdwp=help
-agentpath:<路径名>[=<选项>]
按完整路径名加载本机代理库
-javaagent:<jar 路径>[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument
-splash:<图像路径>
使用指定的图像显示启动屏幕
自动支持和使用 HiDPI 缩放图像
(如果可用)。应始终将未缩放的图像文件名 (例如, image.ext)
作为参数传递给 -splash 选项。
将自动选取提供的最合适的缩放
图像。
有关详细信息, 请参阅 SplashScreen API 文档
@argument 文件
一个或多个包含选项的参数文件
-disable-@files
阻止进一步扩展参数文件
--enable-preview
允许类依赖于此发行版的预览功能
要为长选项指定参数, 可以使用 --<名称>=<值> 或
--<名称> <值>。
javac命令使用:
zxm@zxm-pc:~/testjmod$ javac --help
用法: javac <options> <source files>
其中, 可能的选项包括:
@<filename> 从文件读取选项和文件名
-Akey[=value] 传递给注释处理程序的选项
--add-modules <模块>(,<模块>)*
除了初始模块之外要解析的根模块; 如果 <module>
为 ALL-MODULE-PATH, 则为模块路径中的所有模块。
--boot-class-path <path>, -bootclasspath <path>
覆盖引导类文件的位置
--class-path <path>, -classpath <path>, -cp <path>
指定查找用户类文件和注释处理程序的位置
-d <directory> 指定放置生成的类文件的位置
-deprecation 输出使用已过时的 API 的源位置
--enable-preview 启用预览语言功能。要与 -source 或 --release 一起使用。
-encoding <encoding> 指定源文件使用的字符编码
-endorseddirs <dirs> 覆盖签名的标准路径的位置
-extdirs <dirs> 覆盖所安装扩展的位置
-g 生成所有调试信息
-g:{lines,vars,source} 只生成某些调试信息
-g:none 不生成任何调试信息
-h <directory> 指定放置生成的本机标头文件的位置
--help, -help, -? 输出此帮助消息
--help-extra, -X 输出额外选项的帮助
-implicit:{none,class} 指定是否为隐式引用文件生成类文件
-J<flag> 直接将 <标记> 传递给运行时系统
--limit-modules <模块>(,<模块>)*
限制可观察模块的领域
--module <module-name>, -m <module-name>
只编译指定的模块, 请检查时间戳
--module-path <path>, -p <path>
指定查找应用程序模块的位置
--module-source-path <module-source-path>
指定查找多个模块的输入源文件的位置
--module-version <版本> 指定正在编译的模块版本
-nowarn 不生成任何警告
-parameters 生成元数据以用于方法参数的反射
-proc:{none,only} 控制是否执行注释处理和/或编译。
-processor <class1>[,<class2>,<class3>...]
要运行的注释处理程序的名称; 绕过默认的搜索进程
--processor-module-path <path>
指定查找注释处理程序的模块路径
--processor-path <path>, -processorpath <path>
指定查找注释处理程序的位置
-profile <profile> 请确保使用的 API 在指定的配置文件中可用
--release <release> 针对特定 VM 版本进行编译。支持的目标: 6, 7, 8, 9, 10, 11
-s <directory> 指定放置生成的源文件的位置
-source <release> 提供与指定发行版的源兼容性
--source-path <path>, -sourcepath <path>
指定查找输入源文件的位置
--system <jdk>|none 覆盖系统模块位置
-target <release> 生成特定 VM 版本的类文件
--upgrade-module-path <path>
覆盖可升级模块位置
-verbose 输出有关编译器正在执行的操作的消息
--version, -version 版本信息
-Werror 出现警告时终止编译
java8 使用 --classpath
,而模块化后使用的 --module-path
另:
可以向低版本编译,例,javac -d foo1/ Test1.java Test2.java Test.java -encoding UTF-8 -source 7 -target 7
或 javac -d foo1/ Test1.java Test2.java Test.java -encoding UTF-8 --release 7
虽然说 Java 的向后兼容做得非常非常好, 但是也不是100%兼容,特别是高版本没有 javax 包。
比如,源代码使用 javax.xml.bind.JAXBException
类,使用 jdk11 编译成 jdk7,会编译失败
--release
参数是 jdk 9 开始支持的
使用 java 命令运行程序
zxm@zxm-pc:~/testjmod$ mkdir foo1
zxm@zxm-pc:~/testjmod$ javac -d foo1/ module-info.java Greeting.java Main.java
zxm@zxm-pc:~/testjmod$ java -cp foo1/ com.main.Main
false
zxm@zxm-pc:~/testjmod$ java -p foo1 -m hello.world/com.main.Main
false
zxm@zxm-pc:~/testjmod$ java --module-path foo1 -m hello.world/com.main.Main
false
目录结构:
foo1
com
greeting
Greeting.class
main
Main.class
module-info.class
Greeting.java
Main.java
module-info.java
三、创建 jmod
jar 命令使用
zxm@zxm-pc:~/testjmod$ jar --help
用法: jar [OPTION...] [ [--release VERSION] [-C dir] files] ...
jar 创建类和资源的档案, 并且可以处理档案中的
单个类或资源或者从档案中还原单个类或资源。
示例:
# 创建包含两个类文件的名为 classes.jar 的档案:
jar --create --file classes.jar Foo.class Bar.class
# 使用现有的清单创建档案, 其中包含 foo/ 中的所有文件:
jar --create --file classes.jar --manifest mymanifest -C foo/ .
# 创建模块化 jar 档案, 其中模块描述符位于
# classes/module-info.class:
jar --create --file foo.jar --main-class com.foo.Main --module-version 1.0
-C foo/ classes resources
# 将现有的非模块化 jar 更新为模块化 jar:
jar --update --file foo.jar --main-class com.foo.Main --module-version 1.0
-C foo/ module-info.class
# 创建包含多个发行版的 jar, 并将一些文件放在 META-INF/versions/9 目录中:
jar --create --file mr.jar -C foo classes --release 9 -C foo9 classes
要缩短或简化 jar 命令, 可以在单独的文本文件中指定参数,
并使用 @ 符号作为前缀将此文件传递给 jar 命令。
示例:
# 从文件 classes.list 读取附加选项和类文件列表
jar --create --file my.jar @classes.list
主操作模式:
-c, --create 创建档案
-i, --generate-index=FILE 为指定的 jar 档案生成
索引信息
-t, --list 列出档案的目录
-u, --update 更新现有 jar 档案
-x, --extract 从档案中提取指定的 (或全部) 文件
-d, --describe-module 输出模块描述符或自动模块名称
在任意模式下有效的操作修饰符:
-C DIR 更改为指定的目录并包含
以下文件
-f, --file=FILE 档案文件名。省略时, 基于操作
使用 stdin 或 stdout
--release VERSION 将下面的所有文件都放在
jar 的版本化目录中 (即 META-INF/versions/VERSION/)
-v, --verbose 在标准输出中生成详细输出
在创建和更新模式下有效的操作修饰符:
-e, --main-class=CLASSNAME 捆绑到模块化或可执行
jar 档案的独立应用程序
的应用程序入口点
-m, --manifest=FILE 包含指定清单文件中的
清单信息
-M, --no-manifest 不为条目创建清单文件
--module-version=VERSION 创建模块化 jar 或更新
非模块化 jar 时的模块版本
--hash-modules=PATTERN 计算和记录模块的散列,
这些模块按指定模式匹配并直接或
间接依赖于所创建的模块化 jar 或
所更新的非模块化 jar
-p, --module-path 模块被依赖对象的位置, 用于生成
散列
只在创建, 更新和生成索引模式下有效的操作修饰符:
-0, --no-compress 仅存储; 不使用 ZIP 压缩
其他选项:
-?, -h, --help[:compat] 提供此帮助,也可以选择性地提供兼容性帮助
--help-extra 提供额外选项的帮助
--version 输出程序版本
如果模块描述符 'module-info.class' 位于指定目录的
根目录中, 或者位于 jar 档案本身的根目录中, 则
该档案是一个模块化 jar。以下操作只在创建模块化 jar,
或更新现有的非模块化 jar 时有效: '--module-version',
'--hash-modules' 和 '--module-path'。
如果为长选项提供了必需参数或可选参数, 则它们对于
任何对应的短选项也是必需或可选的。
jmod 命令使用
zxm@zxm-pc:~/testjmod$ jmod --help
用法: jmod (create|extract|list|describe|hash) <选项> <jmod 文件>
主操作模式:
create - 创建新的 jmod 档案
extract - 从档案中提取所有文件
list - 输出所有条目的名称
describe - 输出模块详细信息
hash - 记录绑定模块的散列。
Option Description
------ -----------
-?, -h, --help 输出此帮助消息
--class-path <path> 包含类的应用程序 jar 文件|目录
--cmds <path> 本机命令的位置
--config <path> 用户可编辑配置文件的位置
--dir <path> 提取操作的目标目录
--dry-run 散列模式的模拟运行
--exclude <pattern-list> 排除与所提供逗号分隔的模式列表匹配的文件, 每个元素使用以下格式之一:
<glob 模式>, glob:<glob 模式> 或 regex:<正则
表达式模式>
--hash-modules <regex-pattern> 计算和记录散列, 以将打包模块绑定到与指定 <正则表达式模式> 匹配并直接或间
接依赖于的模块。散列记录在所创建的 JMOD 文件中, 或者记录在
jmod hash 命令指定的模块路径的 JMOD 文件或模块化 JAR
中。
--header-files <path> 标头文件的位置
--help-extra 输出额外选项的帮助
--legal-notices <path> 法律声明位置
--libs <path> 本机库的位置
--main-class <String: class-name> 主类
--man-pages <path> 帮助页的位置
--module-version <module-version> 模块版本
-p, --module-path <path> 模块路径
--target-platform <String: target- 目标平台
platform>
--version 版本信息
@<filename> 从指定文件读取选项
两种方式,第一种,根据生成的 class 文件,先生成 jar 包,再生成 jmod;第二种,根据生成的 class 文件,直接生成 jmod
可指定主类
使用 jar -d -f <jar_file>
可判断一个 jar 包,是不是支持模块化
# zxm@zxm-pc:~/testjmod$ jar --create --file hello.jar --main-class com.main.Main -C foo1/ .
# zxm@zxm-pc:~/testjmod$ jmod create --class-path hello.jar hello.jmod
# zxm@zxm-pc:~/testjmod$ jmod list hello.jmod
# classes/module-info.class
# classes/META-INF/MANIFEST.MF
# classes/com/main/Main.class
# classes/com/greeting/Greeting.class
# zxm@zxm-pc:~/testjmod$ jmod create --class-path foo1/ --main-class com.main.Main hello.jmod
# zxm@zxm-pc:~/testjmod$ jar -d -f hello.jar
# hello.world jar:file:///home/zxm/testjmod/hello.jar/!module-info.class
# requires java.base
# requires java.xml
# contains com.greeting
# contains com.main
# main-class com.main.Main
zxm@zxm-pc:~/testjmod$ jmod create --class-path foo1/ hello.jmod
zxm@zxm-pc:~/testjmod$ jmod list hello.jmod
classes/module-info.class
classes/com/main/Main.class
classes/com/greeting/Greeting.class
四、运行 jmod
zxm@zxm-pc:~/testjmod$ java --module-path hello.jar --module hello.world
false
五、打包 jre 并运行
如果 jmod 中的 MANIFEST.MF 指定 Main-Class,则可使用 jre/bin/java --module hello.world
运行,否则出现 模块 hello.world 不具有 ModuleMainClass 属性,请使用 -m <模块>/<主类>
;如果 jmod 中的 MANIFEST.MF 没有指定 Main-Class,则可使用 jre/bin/java --module hello.world/com.main.Main
zxm@zxm-pc:~/testjmod$ jlink --module-path hello.jmod --add-modules java.base,java.xml,hello.world --output jre/
# zxm@zxm-pc:~/testjmod$ jre/bin/java --module hello.world
# false
zxm@zxm-pc:~/testjmod$ jre/bin/java --module hello.world/com.main.Main
false
java --list-modules
:获取所有可用 jdk 模块的列表
jlink --no-header-files --no-man-pages --compress=2 --add-modules <module-list from step 1> --output java-runtime
:创建一个精简的JRE
jlink
的 --module-path
等效于类路径,告诉JVM在哪里搜索模块,--add-modules
这指定要解决的其他根模块