Java UrlClassLoader未找到服务的ServiceLoader

Java UrlClassLoader未找到服务的ServiceLoader,java,intellij-idea,serviceloader,Java,Intellij Idea,Serviceloader,我试图使用java ServiceLoader和UrlClassLoader从某个jar文件加载插件,但我似乎无法让它找到我的插件类。构建这两个模块都是可行的,但每当我运行下面的代码时,我都会得到一个java.util.NoSuchElementException,即使文件路径正确,我看不出哪里出了问题 我必须测试IntelliJ项目中的模块(加载插件并提供服务提供商的应用程序)和PluginTest(要加载的插件) 这是测试模块结构的屏幕截图: 下面是PluginTest模块结构的屏幕截图:

我试图使用java ServiceLoader和UrlClassLoader从某个jar文件加载插件,但我似乎无法让它找到我的插件类。构建这两个模块都是可行的,但每当我运行下面的代码时,我都会得到一个
java.util.NoSuchElementException
,即使文件路径正确,我看不出哪里出了问题

我必须测试IntelliJ项目中的模块(加载插件并提供服务提供商的应用程序)和PluginTest(要加载的插件)

这是测试模块结构的屏幕截图:

下面是PluginTest模块结构的屏幕截图:

以下是ServiceProvider插件Provider:

package net.lbflabs;
公共抽象类插件提供程序{
公共抽象字符串getSecretMessage(int message);
}
这是扩展此类的插件:

package net.lbflabs.plugins;
导入net.lbflabs.PluginProvider;
公共类PluginClass扩展了PluginProvider{
@凌驾
公共字符串getSecretMessage(int消息){
return“这是我的秘密。”;
}
}
以下是加载插件的主类:

package net.lbflabs;
导入java.io.File;
导入java.net.MalformedURLException;
导入java.net.URL;
导入java.net.URLClassLoader;
导入java.util.ServiceLoader;
公共班机{
私有静态字符串path=“C:/Users/jack/IdeaProjects/Tests/out/artifacts/pluginest\u jar/pluginest.jar”;
publicstaticvoidmain(字符串[]args)引发畸形的DurLexException{
System.out.println(“正在初始化…\n准备从路径“+Path+”加载JAR”);
文件=新文件(路径);
System.out.println(file.exists());//打印为true,因此文件确实存在
URLClassLoader c=新URLClassLoader((新URL[]{file.getAbsoluteFile().toURI().toURL()}));
ServiceLoader=ServiceLoader.load(PluginProvider.class,c);
PluginProvider p=loader.iterator().next();//抛出java.util.NoSuchElementException
System.out.println(“插件中的秘密消息:”+p.getSecretMessage(1));
}
}
以下是运行测试模块时的输出:

"C:\Program Files\Java\jdk-14.0.1\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3\lib\idea_rt.jar=50330:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\jacke\IdeaProjects\Tests\out\production\Tests net.lbflabs.Main
Initializing... 
Preparing to load JAR from Path C:/Users/jacke/IdeaProjects/Tests/out/artifacts/PluginTest_jar/PluginTest.jar...
true
Exception in thread "main" java.util.NoSuchElementException
    at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1310)
    at java.base/java.util.ServiceLoader$2.next(ServiceLoader.java:1298)
    at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1396)
    at net.lbflabs.Main.main(Main.java:19)

Process finished with exit code 1

我认为pluginest模块中的服务文件命名正确(
net.lbflabs.PluginProvider
),并且包含有效的类名(
net.lbflabs.plugins.PluginClass
)。如果它不正确,IntelliJ可能会发现问题,因为当我引入输入错误时,会收到警告

如果有人需要它,我可以提供整个项目作为.rar(请告诉我你希望我如何分享它,例如,我创建一个onedrive链接)


PS:我已经问过这个问题,但是因为我正在处理一个更大的项目,并且犹豫是否要共享其中的所有代码(而且因为我得到的唯一答案不起作用,可能是因为我没有提供足够的信息),我想用一个最小的可行示例来重新发布这个问题,抛出相同的异常,我希望没问题。

我注意到的一件事是,您构造了一个只包含一个类的类加载器。这样,它将无法创建正确的类层次结构,很可能会失败。而是将当前的
Classloader
作为父级传递给
URLClassLoader

ClassLoade parent=PluginProvider.class.getClassLoader();
URL[]URL=新URL[]{file.getAbsoluteFile().toURI().toURL()};
URLClassLoader c=新的URLClassLoader(URL,父级);
现在应该能够构建一个适当的层次结构


另一件事是在项目结构中,您的
META-INF
目录不在包含项目源的
src
目录下。这意味着Intellij会把它们从罐子里放出来。因此,您基本上是添加一个jar,而不添加适当的文件。它只包含类而不包含META-INF/services/net.lbflabs.PluginProvider

类加载器不包含父类,只包含实现类,因此它找不到父类。因此,我怀疑由于不完整的类层次结构,它无法加载该类。因此,您应该使用接受父类装入器并将其设置为当前装入器的构造函数。这样就可以确定一个合适的类层次结构。那么它不会抛出一个不同的异常吗?我有我的类加载器,在类似的情况下有NoClassDefFoundError这样的异常。你可能仍然是对的。我如何解决这个问题?你能把你的补丁发布为答案,这样我就有可能接受它吗?这不是第一次一个异常被另一个异常隐藏,然后查看
LazyClassPathLookupIterator
(一个内部类),它实际上捕获了
ClassNotFoundException
,并简单地返回
null
。导致您得到的异常。谢谢。我确实将PluginProvider类加载器添加到urlclassloader中,但它仍然无法正常工作,但您仍然会得到相同的异常还是不同的异常?或者试试
ClassLoader.getSystemClassLoader
。奇怪的是,我无法复制这个。使用系统或PluginProvider中的类加载器的确切示例确实得到了预期的结果。jar是否实际包含META-INF目录以及服务目录和文件?
META-INF
需要在
src
中,否则它不会导出到jar中。您的jar不包含该文件,因此也不包含插件。我怀疑真正的问题是您原始帖子中的
META-INF
没有在
src
下,这意味着省略了整个结构和服务加载程序文件。当移动到maven时,您可能会将
META-INF
放在
src/main/resources
中。