未设置 -Djava.ext.dirs 时未从目录加载 Java SPI JAR

标签 java jar

我无法让服务提供者接口(interface)从同一目录中的另一个 JAR 加载实现。它仅在我使用 -Djava.ext.dirs= 时有效。在命令行上。没有它就不能工作吗?

我有以下界面:

package playground;

public interface TestIface {
    public String test();
}

这里实现了:

package playground;

public class TestImpl implements TestIface {
    public String test() {
        return "TEST";
    }
}

这里我尝试加载实现:

package playground;
import java.util.Iterator;
import java.util.ServiceLoader;
public class Lalala {
    public static void main(String[] args) {
        ServiceLoader<TestIface> loader = ServiceLoader.load(TestIface.class);
        Iterator<TestIface> it = loader.iterator();
        while (it.hasNext()) {
            TestIface a = it.next();
            System.out.println(a.test());
        }
        System.out.println("DONE");
    }

}

接口(interface)和最后一个类封装在main.jar中,实现在impl.jar中。 main.jar 有主类集,impl.jar 有 META-INF/services/playground.TestIface 文件,其中包含“playground.TestImpl”。两个 JAR 都在同一个目录中。 运行

java -jar main.jar

只打印“完成”,显然没有找到实现。

如果我改为运行

java -Djava.ext.dirs=. -jar main.jar

它还会按预期打印“TEST”。

我做错了什么?为什么除非我更改 java.ext.dirs 设置,否则不会加载其他 JAR 的实现?

最佳答案

java.ext.dirs设置自动将在指定目录中找到的所有 jar 文件添加到主类加载器,这就是 ServiceLoader 可以找到并加载 TestIface.class 的原因(来自 Apidocs:“使用当前线程的上下文类加载器为给定的服务类型创建一个新的服务加载器。”)。

但是你不应该使用 java.ext.dirs为此(请参阅 here 了解其中一种危险)。当你使用 java -jar你不能使用 java -cp设置类路径(您只能使用其中一个)。这使您可以选择使用 URLClassLoader加载其他 jar ,然后调用 ServiceLoader.load(class from another jar) .

提示:要加载其他 jar 文件,请使用 main.jar 的位置文件,如 this question 的答案中所述.其他变量(如启动目录)取决于 Java 的启动方式和位置,很容易导致找不到其他 jar 文件。

关于未设置 -Djava.ext.dirs 时未从目录加载 Java SPI JAR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22737371/

相关文章:

java - 在 JUnit 中设置测试的成本 - 使用模拟对象与遗留代码中的存储库测试

java - Android Studio 文件上的锁定图标

java - 如何使用 JBoss 在 Web 应用程序之间共享库

java - 在带有 Hibernate 的 JAR 中使用 Spring 的困难

java - 为什么我在使用使用 poi jar 的 jar 时遇到 java.lang.NoClassDefFoundError

java - 如何在Netbeans中将maven项目的源代码打包到jar中?

java - 获取 jar 内文件夹内的检索文件

java - 检测多个 BufferedImages Java 的冲突

java - 将 mac jdk 版本设置为 1.8

jar - 使用 SBT 处理库中的非托管类路径 jar,以便依赖项目可以访问它们