从 jar 中调用时,ClassLoader 总是 returns null

ClassLoader always returns null when called from within a jar

我 运行 在通过 maven 从我的代码创建 jar 后遇到了库加载问题。我在 Ubuntu 上使用了 intelliJ idea。我将问题分解为这种情况:

从 idea 中调用以下代码,它会正确打印路径。

package com.myproject;

public class Starter {
    public static void main(String[] args) {
        File classpathRoot = new File(Starter.class.getResource("/").getPath());
        System.out.println(classpathRoot.getPath());
    }
}

输出为:

/home/ted/java/myproject/target/classes

当我调用 mvn install 并尝试使用以下命令从命令行 运行 它时,我得到一个 NullPointerException 因为 class.getResource() returns null:

cd /home/ted/java/myproject/target/
java -cp myproject-0.1-SNAPSHOT.jar com.myproject.Starter

调用相同:

cd /home/ted/java/myproject/target/
java -Djava.library.path=. -cp myproject-0.1-SNAPSHOT.jar com.myproject.Starter

我改用class.getClassLoader().getRessource("")也没关系。通过 class.getClassLoader().getRessource("file.txt").

访问目标目录内的单个文件时出现同样的问题

我想用这种方式加载同一目录中的本机文件(而不是从 jar 内部)。我的方法有什么问题?

JVM 中的class路径加载机制具有高度可扩展性,因此通常很难保证一种方法适用于所有情况。例如在你的 IDE 中起作用的东西在容器中 运行 时可能不起作用,因为你的 IDE 和你的容器可能具有高度专业化的 class 加载程序,具有不同的要求。

您可以采用两层方法。如果上述方法失败,您可以从系统属性中获取 classpath,并扫描它以查找您感兴趣的 jar 文件,然后从该条目中提取目录。

例如

public static void main(String[] args) {
    File f = findJarLocation("jaxb-impl.jar");
    System.out.println(f);
}

public static File findJarLocation(String entryName) {

    String pathSep = System.getProperty("path.separator");

    String[] pathEntries = System.getProperty("java.class.path").split(pathSep);
    for(String entry : pathEntries) {
        File f = new File(entry);
        if(f.getName().equals(entryName)) {
            return f.getParentFile();
        }
    }
    return null;
}