具有UrlClassLoader的ServiceLoader找不到服务 [英] ServiceLoader with UrlClassLoader not finding service

查看:76
本文介绍了具有UrlClassLoader的ServiceLoader找不到服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用带有UrlClassLoader的java ServiceLoader从某个jar文件中加载插件,但似乎无法找到它来找到我的插件类.构建两个模块都可以,但是每当我运行下面的代码时,即使文件路径正确并且看不到混乱的地方,我都会得到 java.util.NoSuchElementException

我必须在IntelliJ项目, Test (加载插件并提供ServiceProvider的应用程序)和 PluginTest (要加载的插件)中进行模块./p>

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

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

这是ServiceProvider的PluginProvider:

  package net.lbflabs;公共抽象类PluginProvider {公共抽象字符串getSecretMessage(int message);} 

这是扩展此类的插件:

  package net.lbflabs.plugins;导入net.lbflabs.PluginProvider;公共类PluginClass扩展了PluginProvider {@Overridepublic String getSecretMessage(int message){返回这是我的秘密".}} 

这是加载插件的主要类:

  package net.lbflabs;导入java.io.File;导入java.net.MalformedURLException;导入java.net.URL;导入java.net.URLClassLoader;导入java.util.ServiceLoader;公共班级主要{私有静态字符串路径="C:/用户/jacke/IdeaProjects/Tests/out/artifacts/PluginTest_jar/PluginTest.jar";公共静态void main(String [] args)抛出MalformedURLException {System.out.println(正在初始化... \ n正在准备从路径" +路径+"..."加载JAR);文件文件=新文件(路径);System.out.println(file.exists());//打印为true,因此文件确实存在URLClassLoader c =新的URLClassLoader((新的URL [] {file.getAbsoluteFile().toURI().toURL()}));ServiceLoader< PluginProvider>loader = ServiceLoader.load(PluginProvider.class,c);PluginProvider p = loader.iterator().next();//引发java.util.NoSuchElementExceptionSystem.out.println(插件中的秘密消息:" + p.getSecretMessage(1));}} 

这是运行测试"模块时的输出:

 "C:\ Program Files \ Java \ jdk-14.0.1 \ bin \ java.exe""-javaagent:C:\ Program Files \ JetBrains \ IntelliJ IDEA社区版2020.3 \ lib \ idea_rt.jar = 50330:C:\ Program Files \ JetBrains \ IntelliJ IDEA社区版2020.3 \ bin"-Dfile.encoding = UTF-8 -classpath C:\ Users \ jacke \ IdeaProjects \ Tests \ out \ production \ Tests net.lbflabs.Main初始化中...正在准备从路径C加载JAR:/Users/jacke/IdeaProjects/Tests/out/artifacts/PluginTest_jar/PluginTest.jar ...真的线程"main"中的异常java.util.NoSuchElementException在java.base/java.util.ServiceLoader $ 2.next(ServiceLoader.java:1310)在java.base/java.util.ServiceLoader $ 2.next(ServiceLoader.java:1298)在java.base/java.util.ServiceLoader $ 3.next(ServiceLoader.java:1396)在net.lbflabs.Main.main(Main.java:19)流程以退出代码1完成 

我相信PluginTest模块中的服务文件已正确命名( net.lbflabs.PluginProvider ),并包含有效的类名( net.lbflabs.plugins.PluginClass ).如果不正确,则IntelliJ可能会找到问题,因为当我输入错字时会收到警告.

如果有人需要它,我可以将整个项目提供为.rar(请告诉我您要如何共享它,例如,我创建了一个单驱动器链接)

PS:我已经在此处提出了这个问题,但是由于我正在做一个更大的项目,并且不愿共享其中的所有代码(并且由于我得到的唯一答案没有用,可能是由于我没有足够的信息),所以我想用一个最小的可行示例重新发布该问题.会抛出同样的异常,我希望很好.

解决方案

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

  ClassLoade parent = PluginProvider.class.getClassLoader();URL [] urls =新URL [] {file.getAbsoluteFile().toURI().toURL()};URLClassLoader c =新的URLClassLoader(URL,父级); 

现在应该可以构建适当的层次结构.

另一件事是在您的项目结构中,您的 META-INF 目录不在包含项目源的 src 目录下.这意味着Intellij会将其从罐子中取出.因此,您基本上是在没有的情况下添加一个jar文件.它仅包含类,而不包含 META-INF/services/net.lbflabs.PluginProvider .

I am trying to load plugins from a certain jar file using the java ServiceLoader with an UrlClassLoader, but I just cannot seem to get it to find my plugin classes. Building both modules works, but whenever I run the code below, I get a java.util.NoSuchElementException, even though the file path is correct and I do not see where I messed up

I have to modules in my IntelliJ project, Test (The application loading the plugin and also providing the ServiceProvider) and PluginTest (The plugin to be loaded).

This is a screenshot of the structure of the Test module:

And here is a screenshot of the structure of the PluginTest module:

Here is the ServiceProvider PluginProvider:

package net.lbflabs;

public abstract class PluginProvider {

    public abstract String getSecretMessage(int message);
}

This is the plugin that extends this class:

package net.lbflabs.plugins;

import net.lbflabs.PluginProvider;

public class PluginClass extends PluginProvider {
    @Override
    public String getSecretMessage(int message) {
        return "Here is my secret.";
    }
}

Here is the main class that loads the plugin:

package net.lbflabs;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ServiceLoader;

public class Main {

    private static String path = "C:/Users/jacke/IdeaProjects/Tests/out/artifacts/PluginTest_jar/PluginTest.jar";

    public static void main(String[] args) throws MalformedURLException {
        System.out.println("Initializing... \nPreparing to load JAR from Path " + path + "...");
        File file = new File(path);
        System.out.println(file.exists()); //Prints true, so file does exist
        URLClassLoader c = new URLClassLoader((new URL[]{file.getAbsoluteFile().toURI().toURL()}));
        ServiceLoader<PluginProvider> loader = ServiceLoader.load(PluginProvider.class, c);
        PluginProvider p = loader.iterator().next(); // Throws the java.util.NoSuchElementException
        System.out.println("Secret message in plugin: " + p.getSecretMessage(1));
    }
}

Here is the output when running the Tests module:

"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

The service file in the PluginTest module I believe is correctly named (net.lbflabs.PluginProvider) and contains the valid class name (net.lbflabs.plugins.PluginClass). If it was incorrect, IntelliJ would probably find the issue since when I introduce a typo I get warnings.

If someone needs it, I can provide the whole project as .rar (please tell me how you want me to share it, e.g. I create a onedrive link)

PS: I have already asked this question here, but since I was working on a bigger project and hesitant to share all the code in it (and since the only answer I got did not work, probably due to not enough info from me), I wanted to repost the issue with a minimum workable example that throws the same exception, I hope that is fine.

解决方案

One thing I notice is that you construct a classloader which only contains 1 class. With this it won't be able to create a proper class hierarchy and most likely fail. Instead pass the current Classloader as the parent to your URLClassLoader.

ClassLoade parent = PluginProvider.class.getClassLoader();
URL[] urls = new URL[] { file.getAbsoluteFile().toURI().toURL()};
URLClassLoader c = new URLClassLoader(urls, parent);

Now a proper hierarchy should be able to be constructed.

Another thing is in your project structure your META-INF directory isn't under the src directory containing the sources for the project. Which means Intellij will leave them out of the jar. So you are basically adding a jar without the proper files. It contains only the class and not META-INF/services/net.lbflabs.PluginProvider.

这篇关于具有UrlClassLoader的ServiceLoader找不到服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆