我正在尝试创建一个收缩Java映像,用于使用jdeps
和jlink
(即只有运行Minecraft所需的最低Java模块),但是我遇到了错误,我希望得到一些指导。我是这样做的:
我将1.20.1 manifest中列出的库下载到我的~/.minecraft/库中,并将client.jar
下载到~/. minecraft/versions/1.20.1/1.20.1.jar中。
为了找到Minecraft客户端使用的Java模块,我运行:
jdeps \
-q \
--ignore-missing-deps \
--print-module-deps \
--multi-release 17 \
-cp $HOME'/.minecraft/libraries/*' \
--recursive \
$HOME/.minecraft/versions/1.20.1/1.20.1.jar
这给了我:
java.base,java.compiler,java.desktop,java.management,java.naming,java.rmi,java.scripting,java.security.jgss,java.sql,jdk.jfr,jdk.unsupported
然后我将这些模块作为$modules
传递给jlink
:
jlink --no-header-files --compress=2 --no-man-pages --add-modules $modules --output 'custom-jre'
最后,我像往常一样运行Minecraft客户端,但现在使用我新创建的收缩JVM
/path/to/custom-jre/bin/java \
-cp '<whole-list-of-minecraft-jars>' \
net.minecraft.client.main.Main \
--version 1.20.1 \
--gameDir $HOME/.minecraft \
--accessToken <auth-token>
崩溃并显示错误消息:
Exception in thread "main" java.lang.ExceptionInInitializerError
at net.minecraft.client.main.Main.main(SourceFile:83)
Caused by: java.lang.IllegalStateException: No jar file system provider found
at ac.o(SourceFile:101)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at ac.<clinit>(SourceFile:101)
... 1 more
如您所见,客户端成功启动,但在Minecraft源代码中的某个位置存在未处理的异常。
使用MCP(Minecraft源代码的反编译版本),我设法找到了抛出错误的相关代码:
// src/main/java/net/minecraft/Util.java
public class Util {
// ....
public static final FileSystemProvider ZIP_FILE_SYSTEM_PROVIDER = FileSystemProvider.installedProviders().stream().filter((p_201865_) -> {
return p_201865_.getScheme().equalsIgnoreCase("jar");
}).findFirst().orElseThrow(() -> {
return new IllegalStateException("No jar file system provider found");
});
// ....
}
我对Java文件系统不是很熟悉,但它基本上找不到“jar”文件系统提供程序。我写了这段简短的代码来说明这个问题:
import java.nio.file.spi.FileSystemProvider;
public class Test {
public static void main(String[] args) {
for (var provider : FileSystemProvider.installedProviders()) {
System.out.println(provider.getScheme().toString());
}
}
}
# Running with the system's JDK 17.0.8 (~259M)
$ java Test
file
jar
jrt
# Running it with my custom JRE: (~58M)
$ /path/to/custom-jre/bin/java Test
file
jrt # <- doesn't have the jar file system
我在这里描述的方法在我的每个项目中都有效,只有Minecraft导致了这个问题。如果有更好的方法,我很乐意看到它!
那么,什么是适当的解决方案呢?我是不是漏了什么?这个“jar文件系统”是在哪里定义的?任何帮助都是受欢迎的,谢谢提前:)
1条答案
按热度按时间rqqzpn5f1#
将模块
jdk.zipfs
添加到您的列表中,该模块应提供zip Filesystem。另请参阅jdk.zipfs文档,并检查
jdeps
是否可以帮助您缩小更多的依赖关系。更新
您似乎已经正确地使用了
jdeps
来分析模块依赖关系,但不幸的是,它无法帮助动态代码依赖关系,例如基于反射,服务或其他类加载。您可以使用
jdeps
而不使用摘要依赖项--print-module-deps
来打印更详细的列表,这样可能给予依赖模块中的包中的服务提供者-例如java.nio.file.spi
如下所示:您可以通过搜索上面链接的JDK文档中的包名称来找到提供程序名称。然后,您可以使用
jlink
的选项来建议缺少的服务提供程序实现,例如java.nio.file.spi.FileSystemProvider
:另一个经常导致jlink打包问题的缺少提供程序是代码需要额外的字符集支持的地方: