为了账号安全,请及时绑定邮箱和手机立即绑定

Java 从目录中加载 jar 文件

Java 从目录中加载 jar 文件

胡子哥哥 2022-09-14 17:59:05
我目前正在开发一个开源项目,人们可以添加自己的.jar来扩展所包含的功能。但是,我一直坚持如何在jar中加载类。我有一个抽象类,它有一个抽象方法和一些getter,它提供了一些对象来处理应用程序。该插件需要子类我的插件类。jar应该添加到/plugins中,因此我希望在应用程序启动时加载/plugins文件夹中的所有*.jar文件。onEnable()BasePlugin我现在遇到的问题是,在我发现的所有方法中,我需要在jar文件中声明类的类路径,我不知道。我也不知道 jar 文件的名称。因此,我需要扫描 /plugins 文件夹中的任何 *.jar 文件,并在实现和调用该方法的 jar 中加载相应的类。BasePluginonEnable()
查看完整描述

4 回答

?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

基本思想也是...

  1. 读取特定目录中的所有文件

  2. 将每个结果的引用转换为FileURL

  3. 使用与结果一起设定种子的 ,加载每个结果URLClassLoaderURL

  4. 用于查找具有特定名称的所有匹配资源URLClassLoader#findResources

  5. 迭代匹配的资源并加载每个资源,这至少应该给出“入口点”类名

  6. 装入由“入口点”属性指定的类

例如。。。

public List<PluginClass> loadPlugins() throws MalformedURLException, IOException, ClassNotFoundException {

    File plugins[] = new File("./Plugins").listFiles(new FileFilter() {

        @Override

        public boolean accept(File file) {

            return file.getName().endsWith(".jar");

        }

    });

    List<URL> plugInURLs = new ArrayList<>(plugins.length);

    for (File plugin : plugins) {

        plugInURLs.add(plugin.toURI().toURL());

    }

    URLClassLoader loader = new URLClassLoader(plugInURLs.toArray(new URL[0]));

    Enumeration<URL> resources = loader.findResources("/META-INFO/Plugin.properties");

    List<PluginClass> classes = new ArrayList<>(plugInURLs.size());

    while (resources.hasMoreElements()) {

        URL resource = resources.nextElement();

        Properties properties = new Properties();

        try (InputStream is = resource.openStream()) {

            properties.load(is);

            String className = properties.getProperty("enrty-point");

            PluginClass pluginClass = loader.loadClass(className);

            classes.add(pluginClass);

        }

    }

    return classes

}

nb:我没有运行这个,但这是“基本”


查看完整回答
反对 回复 2022-09-14
?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

SpigotMC也使用JAR文件作为插件,jar内部是一个文件,用于存储有关插件的额外信息,包括类路径。您不需要使用 YAML 文件,而是可以使用 JSON 甚至纯文本文件之类的文件。plugin.yaml

YAML 文件位于 jar 中,可以使用此处介绍的一些方法来访问该文件。然后,您可以获取类路径属性,然后使用此处介绍的方法加载 jar。可以存储有关插件的额外信息,例如名称,版本和依赖项。


查看完整回答
反对 回复 2022-09-14
?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

Java已经有一个这样的类:服务加载器。


服务加载器类是随 Java 6 引入的,但“SPI jar”概念实际上与 Java 1.3 一样古老。这个想法是每个jar都包含一个简短的文本文件,该文件描述了其特定服务提供者接口的实现。


例如,如果一个.jar文件包含两个名为 FooPlugin 和 BarPlugin 的 BasePlugin 子类,则该.jar文件还将包含以下条目:


META-INF/services/com.example.BasePlugin

该 jar 条目将是一个文本文件,包含以下行:


com.myplugins.FooPlugin

com.myplugins.BarPlugin

您的项目将通过创建一个从目录中读取的类加载器来扫描插件:plugins


Collection<URL> urlList = new ArrayList<>();


Path pluginsDir = Paths.get(

    System.getProperty("user.home"), "plugins");


try (DirectoryStream<Path> jars =

    Files.newDirectoryStream(pluginsDir, "*.jar")) {


    for (Path jar : jars) {

        urlList.add(jar.toUri().toURL());

    }

}


URL[] urls = urlList.toArray(new URL[0]);

ClassLoader pluginClassLoader = new URLClassLoader(urls,

    BasePlugin.class.getClassLoader());


ServiceLoader<BasePlugin> plugins =

    ServiceLoader.load(BasePlugin.class, pluginClassLoader);


for (BasePlugin plugin : plugins) {

    plugin.onEnable();

    // etc.

}

使用 ServiceLoader 的另一个优点是,您的代码将能够与模块一起使用,这是 Java 9 引入的更完整的代码封装形式,可提供更高的安全性。


查看完整回答
反对 回复 2022-09-14
?
哆啦的时光机

TA贡献1779条经验 获得超6个赞

这里有一个例子,它可能会有所帮助。另外,你应该看看OSGi。


查看完整回答
反对 回复 2022-09-14
  • 4 回答
  • 0 关注
  • 199 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信