对JVM Jar打开进行故障排除

时间:2018-07-26 02:51:49

标签: java jvm classpath classloading

我有一个很小的Java程序“ Test.java”,它依赖于在同一目录的单独jar文件中找到的类“ TestLib”。

“项目”结构:

$ ls
Test.java   Test.class   testlib.jar

Test.java和testlib.jar是存根工件,再现了我在更大的应用程序中看到的类路径问题。 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

编译这个小项目

我尝试使用命令java -classpath .:testlib.jar Test运行它,并获得输出:

Before instantiating testlib
Exception in thread "main" java.lang.NoClassDefFoundError: com/TestLib at Test.main(Test.java:6)

找不到“ TestLib”!

有趣的是,当我在Java调用中添加-verbose标志时,我发现它甚至从未打开我的库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内容阻止JVM打开jar?我应该采取什么步骤解决为什么在运行时找不到“ TestLib”的问题?

1 个答案:

答案 0 :(得分:0)

就我而言,由于我的JAR中存在META-INF/INDEX.LIST文件,我看到了这种情况。

该文件(如果存在)包含JAR中可用的类文件列表。我的INDEX.LIST文件不完整,没有提及我的TestLib类。因此,当ClassLoader进行查找时,他们相信INDEX.LIST中的jar内容列表,并报告找不到该类。

((由于Gradle的“ shadow”插件的一些非常规(读取,错误)用法,我最终得到了一个不完整的INDEX.LIST。默认情况下,shadow插件在构建有阴影的jar时会删除所有INDEX.LIST文件,但是我不小心将其配置为不执行此操作。因此,如果您在有阴影的jar中看到此行为,则可能是原因。)