当前位置: 首页 > 面试题库 >

使用ServiceLoader动态加载插件jar

楚俊逸
2023-03-14
问题内容

我正在尝试为我的应用程序创建一个插件系统,我想从简单的事情开始。每个插件都应打包在.jar文件中并实现SimplePlugin接口:

package plugintest;

public interface SimplePlugin {
    public String getName();
}

现在,我创建了一个SimplePlugin打包为.jar的实现,并将其放在主应用程序的plugin /子目录中:

package plugintest;

public class PluginTest implements SimplePlugin {
    public String getName() {
        return "I'm the plugin!";
    }
}

在主应用程序中,我想获取一个实例PluginTest。我尝试了两种选择,都使用java.util.ServiceLoader

1.动态扩展类路径

这使用已知的技巧在系统类加载器上使用反射来避免封装,从而添加URL类路径。

package plugintest.system;

import plugintest.SimplePlugin;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceLoader;

public class ManagePlugins {
    public static void main(String[] args) throws IOException {
        File loc = new File("plugins");
        extendClasspath(loc);

        ServiceLoader<SimplePlugin> sl = ServiceLoader.load(SimplePlugin.class);
        Iterator<SimplePlugin> apit = sl.iterator();
        while (apit.hasNext())
            System.out.println(apit.next().getName());
    }

    private static void extendClasspath(File dir) throws IOException {
        URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        URL urls[] = sysLoader.getURLs(), udir = dir.toURI().toURL();
        String udirs = udir.toString();
        for (int i = 0; i < urls.length; i++)
            if (urls[i].toString().equalsIgnoreCase(udirs)) return;
        Class<URLClassLoader> sysClass = URLClassLoader.class;
        try {
            Method method = sysClass.getDeclaredMethod("addURL", new Class[]{URL.class});
            method.setAccessible(true);
            method.invoke(sysLoader, new Object[] {udir});
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

plugins /目录已按预期添加(因为可以检查sysLoader.getURLs()),但是该ServiceLoader对象给出的迭代器为空。

2.使用URLClassLoader

这使用ServiceLoader.load带有类的第二个参数的另一个定义ClassLoader

package plugintest.system;

import plugintest.SimplePlugin;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceLoader;

public class ManagePlugins {
    public static void main(String[] args) throws IOException {
        File loc = new File("plugins");

        File[] flist = loc.listFiles(new FileFilter() {
            public boolean accept(File file) {return file.getPath().toLowerCase().endsWith(".jar");}
        });
        URL[] urls = new URL[flist.length];
        for (int i = 0; i < flist.length; i++)
            urls[i] = flist[i].toURI().toURL();
        URLClassLoader ucl = new URLClassLoader(urls);

        ServiceLoader<SimplePlugin> sl = ServiceLoader.load(SimplePlugin.class, ucl);
        Iterator<SimplePlugin> apit = sl.iterator();
        while (apit.hasNext())
            System.out.println(apit.next().getName());
    }
}

再一次,迭代器再也没有“ next”元素。

我肯定会缺少某些东西,因为这是我第一次“玩”类路径和加载。


问题答案:

问题很简单。又傻 在插件.jar文件中/services/plugintest.SimplePluginMETA- INF目录内缺少该文件,因此ServiceLoader无法将jar识别为服务并加载类。

几乎就是所有,第二种方法(和更清洁的方法)就像一种魅力。



 类似资料:
  • 本文向大家介绍bootstrap table插件动态加载表头,包括了bootstrap table插件动态加载表头的使用技巧和注意事项,需要的朋友参考一下 bootstrap的table属性已经很熟悉了,最近遇到一个问题,犹豫每个列表加载的数据需求不同,所以需要动态的更换表头。 网上有很多加载表格数据的例子,但是却没有找到如何动态加载表格,再加在数据。 虽然可以一个表格加载一种数据,但是本着学习的

  • 问题内容: 我已经编写了一个PropertyUtils类(来自互联网),它将加载属性 而PropertiesUtil类如下所示 稍后,我可以通过调用PropertiesUtil.getProperty()方法来获取属性。 但是现在我要稍作修改,以便如果myApp.properties被用户修改/更改,则应再次加载 可能我需要FileWatcher类 但我的怀疑是 如何使用classpath:myA

  • 我已经写了一个PropertyUtils类(来自互联网),它将加载属性 PropertiesUtil类如下所示 稍后,我可以通过调用PropertiesUtil来获取属性。getProperty()方法。 但现在我想稍微修改一下,如果myApp。属性被用户修改/更改,应该重新加载 可能我需要FileWatcher类 但我的疑虑是 如何使用classpath创建File对象:myApp/myApp.

  • 本文向大家介绍java动态加载插件化编程详解,包括了java动态加载插件化编程详解的使用技巧和注意事项,需要的朋友参考一下 前言 对于java程序员来说,插件化是一件很酷的功能,小二有幸在工作中实现了此功能。 背景: 需要将mysql的数据通过canal同步至kafka/mysql/hdfs等 实现 然后就可以进行插件的调用了。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持

  • 问题内容: 如何可靠,动态地加载JavaScript文件?这将用于实现模块或组件,该模块或组件在“初始化”时将根据需要动态加载所有需要的JavaScript库脚本。 使用该组件的客户端不需要加载实现该组件的所有库脚本文件(并将标记手动插入其网页),只需加载“主”组件脚本文件即可。 主流JavaScript库如何做到这一点(原型,jQuery等)? 这些工具是否将多个JavaScript文件合并到脚

  • 问题内容: 我正在考虑构建一个Web应用程序,人们可以在其中安装插件。我希望插件能够定义将呈现到页面的React组件,而无需在安装插件后重新编译主JavaScript包。 所以这是我正在考虑的方法: 使用webpack 将主要的JavaScript与React作为外部库捆绑在一起。 也让插件作者使用React作为外部库来编译其组件。 这样,我只运行一个React实例。我可能可以对其他一些经常使用的