如何将java类文件包含为从程序中的外部文件夹运行的插件

时间:2018-04-13 11:59:56

标签: java class plugins classloader external

我正在为我的大学工作制作一个终端/命令提示符类型的程序,我想在文件库中包含一个名为“plugins”的单独文件夹,在那里我可以创建新的类文件并将它们放在那里为我的程序添加新的特性和功能,而无需编辑它的源代码。我试过使用类加载器,但我不知道如何使用它来从外部.java文件中运行方法。这可能吗,任何人都可以帮助我吗?

提前致谢

2 个答案:

答案 0 :(得分:0)

我不知道你想用这个来实现什么。我认为是某种插件系统。通常这不是获得灵活性的正确方法。如果您发布更多详细信息,答案可能更准确。

这里有两个不同的问题。

首先,您要从程序外部的文件夹中加载类。您可以修改程序的类路径以在RUNTIME加载该类。您需要修改程序中的清单文件。

其次,您希望在程序中使用已加载的类。那是一个不同的野兽。如果您使用Spring框架,实现此目的的一种方法是外部文件夹中的jar包含一个众所周知的xml文件,其中要使用的类将作为bean注入。实现此目的的其他方法是制作自定义注释并使用反射注入类。

答案 1 :(得分:0)

您可以手动或使用框架来完成此操作,具体取决于您的需求。如果您的项目不仅仅是一个玩具项目,请使用框架。

警告:我做过一次这样的事情(手工)。除非我认为我的应用程序将被广泛传播并由非常不同的人使用,否则我不会再这样做了。如果您想要添加新功能,只需添加它,重新编译并发布新版本。

警告2:在这两种情况下,您都必须考虑安全问题(如何构建沙箱?),冲突(如果两个插件使用相同的资源,您的应用程序应该做什么?)和依赖性(如果你的插件取决于外部库或其他插件,如何加载它们?)。

使用框架

我发现this看起来很有前途并且使用注释,但还有许多其他可能性(我从未使用OSGi,但为什么不呢?)。

手工

我给你一个草图;在一个真实的项目中,它可能更复杂。我会忽略安全问题。

大图

您必须在应用程序的正常过程中定义一些钩子。每个钩子都与一个动作相关联。经典示例:在保存文件之前,您的应用程序会调用beforeSave挂钩,即beforeSave方法,或者当您的应用程序创建菜单时,它会调用addNewItems方法。应用程序负责加载插件。插件有责任执行操作。

理解这种机制的最好方法是看一些PHP CMS:MediaWiki,Wordpress,......都建立在这个模型上。

在编译时

您的应用程序具有与某些方法调用相对应的钩子。那些方法调用由插件处理。因此,您必须在应用程序和这些插件之间创建合同。在Java中,此契约将是一个或多个定义以下方法的接口:

  • 您的申请将致电
  • 你的插件将实现。

显然,每个插件和你的应用程序都知道这个(这些)接口,在编译时(你应该把它包含在你的应用程序和每个插件中)。 / p>

在运行时

初始化:加载插件

您的插件是包含一些实现一个或多个接口的类的jar。对于插件目录中的每个jar,您必须列出实现一个或多个接口的类,并选择将加载和实例化的接口。

可以通过几个步骤完成:

  1. 您的应用程序扫描插件目录并为每个jar文件创建一个JarFile对象。
  2. 对于每个JarEntry,如果jar条目以.class结尾,则应用程序构建类名并使用类加载器(ClassLoader.loadClass)加载类。
  3. 如果类实现了其中一个接口,则应用程序将存储该类。
  4. 您的应用程序现在有一个地图,它将一组类与每个接口相关联。
  5. 如果许多类实现相同的接口,则需要一种机制来定义优先级,解决冲突和依赖关系。对于优先级,这可以是配置文件,由接口本身定义的优先级值,类的名称(02之前的01),...您选择,对于每个实现的接口,正确的类和将它(它们)加载到实数(ClassLoader.forName),然后实例化它(和依赖项)。

    有些图书馆可以帮助您反思:我喜欢Guava

    当应用程序遇到挂钩

    现在,您有一个或多个实现该接口的类实例。每次你的应用程序遇到一个钩子时,它会检查它是否有可能使用的对象。如果是这种情况,它会调用与钩子相对应的方法。

    如上所述,这仅适用于玩具项目,但应该有效。您可以添加安全检查,插件加载/卸载等。