我无法让服务提供者接口(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/