java - 排除 JVM Jar 打开问题
问题描述
我有一个小型 Java 程序“Test.java”,它依赖于在同一目录中的单独 jar 文件中找到的类“TestLib”。
“项目”结构:
$ ls
Test.java Test.class testlib.jar
Test.java 和 testlib.jar 是 stub 工件,它们重现了我在更大的应用程序中看到的类路径问题。Test.java 所做的只是从 testlib.jar 实例化一个类,然后退出:
import com.TestLib;
public class Test {
public static void main(String[] args) {
System.out.println("Before instantiating testlib");
new TestLib();
System.out.println("After instantiating testlib");
}
}
我的测试 jar 有问题的测试库类:
$ unzip -l testlib.jar
...
com/TestLib.class
...
(jar 包含许多其他类和 meta-inf 文件,此处省略)
我可以编译这个小项目:javac Test.java -classpath .:testlib.jar
我尝试使用 command 运行它java -classpath .:testlib.jar Test
,并获得输出:
Before instantiating testlib
Exception in thread "main" java.lang.NoClassDefFoundError: com/TestLib at Test.main(Test.java:6)
它找不到“TestLib”!
有趣的是,当我将-verbose
标志添加到我的 java 调用时,我可以看到它甚至从未打开我的库 jar 以在那里查找 TestLib:
$ java -verbose -classpath .:testlib.jar Test 2>&1 | grep "Opened"
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jsse.jar]
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jce.jar]
是什么决定了 JVM 是否打开一个 jar 文件来查找丢失的类?是否有任何 META-INF 或其他 jar 内容阻止 jar 被 JVM 打开?我应该采取哪些步骤来解决为什么在运行时找不到“TestLib”?
解决方案
就我而言,我看到这种行为是因为META-INF/INDEX.LIST
我的 JAR 中存在一个文件。
该文件(如果存在)包含 JAR 中可用的类文件列表。我的 INDEX.LIST 文件不完整,并且没有提到我的TestLib
班级。所以当 ClassLoaders 来找时,他们相信 jar 内容列表INDEX.LIST
,并报告他们找不到类。
(由于对 Gradle 的“shadow”插件的一些非常规(读取,不正确)使用,我最终得到了一个不完整INDEX.LIST
的结果。默认情况下,shadow 插件在构建阴影 jar 时会删除任何 INDEX.LIST 文件,但我不小心将其配置为不这样做。因此,如果您在有阴影的罐子中看到这种行为,这可能是原因。)
推荐阅读
- google-cloud-platform - 无法从 GCP Marketplace 部署 - 缺少有效的默认服务帐号
- c# - datagridview中的两个日期数据差异
- gitahead - 如何在 GitAhead 中暂存单行
- python - 卡在使用 keras.models 的 load_models 加载 facenet-keras 模型
- python - Python 3 - 如何将字符串中的每个字符拆分成一个列表,同时保持十进制数字不变?
- istio - 为 Istio ingress-gateway Loadbalancer 服务分配静态公共 IP
- node.js - 在查询结果中解析服务器未定义的列值
- r - 我怎样才能画出平均值?
- ios - Fyber 奖励视频和优惠墙 iOS
- google-cloud-platform - 解释 Stackdriver Metrics 的意思是“每 60 秒采样一次。采样后,最长 240 秒内数据不可见”