【问题标题】:Finding new Java class at runtime在运行时查找新的 Java 类
【发布时间】:2010-07-22 14:32:08
【问题描述】:

我希望为客户提供我们正在准备的软件模型的功能 - 我想知道它是否是

  1. 可能
  2. 智能(又名不傻)
  3. 最好的东西

我希望客户能够编写一个实现我的Computable 接口的java 类并将其粘贴在某个预定文件夹中。此文件夹将包含 .java 文件而不是 .class 文件。然后,在运行时,我希望我的程序搜索该文件夹并从该文件夹中提取所有Computables,并将它们存储在从Computable 名称到Computable 对象的映射中。 Computable 应该只有一个默认构造函数,并且它的接口只有一个名为 compute 的方法,它将 Object 的数组映射到 Object

【问题讨论】:

  • 你想在运行时编译用户的文件吗?
  • 必须是语言本身,还是其他脚本语言也可以?
  • @jedierikb 如果在运行时编译足够容易,那很好。我只是不想让客户担心拖拽类文件。
  • @skaffman Java 友好客户...应该坚持使用 Java
  • 甚至不是与 java 紧密相关的脚本语言,例如 groovy?

标签: java


【解决方案1】:

Java SE 6 中引入的Java Compiler API 应该可以满足您的需求。

【讨论】:

  • 请注意,此 API 仅在 JDK 中可用,在 JRE 中不可用。因此,如果您打算分发它,最终用户/客户端必须已经安装了 JDK,这在主要公众中非常罕见。
  • @BalusC javax 末尾的“x”是否总是暗示这一点?
  • 不,并非总是如此。有些是(成为)标准 Java SE API 的一部分,有些则不是。
【解决方案2】:

您可能会发现Google Reflections 对于在类路径中查找实现/扩展某个接口/超类的类很有用。然后就很简单了

Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class);

然后,要测试它是否确实有一个无参数的默认构造函数,只需检查每个 Class#newInstance() 是否没有抛出任何异常。

【讨论】:

  • 如果 .class 文件不在当前路径中,而是在我们仅在运行时了解的文件夹中怎么办?
  • 您可以在运行时使用URLClassLoader向类路径添加路径。
【解决方案3】:

提供了几个建议作为对this question 的回答。

这里也是On-the-fly, in-memory java code compilation for Java 5 and Java 6

【讨论】:

    【解决方案4】:

    如果在运行时编译足够容易,那很好。

    您可以根据需要使用javax.tools 进行编译。 Create dynamic applications with javax.tools 也可能有帮助。也可以in memory.

    一个警告:使用编译器会创建对 JDK 的依赖;仅 JRE 是不够的。

    【讨论】:

    • 您有示例代码吗?我是否从 Java 处理命令行来执行 javac?我认为如何吸入类文件并构造类?
    【解决方案5】:

    【讨论】:

    • 看起来很有希望,但它似乎围绕着两种可能的解决方案。 1)使用某个人为自己构建的 API(我不想在我离开的短时间内冒险使用其他人的框架。)或 2)使用反射来确定哪些已经加载的类实现了 Computable。回想一下,我的类不会被加载......它们只是 .java 文件。
    【解决方案6】:

    认为如果您允许您的客户使用 Groovy 之类的东西键入代码声明,这会更简单,这足够 Java 风格,并且在运行时易于从 String 值执行。

    【讨论】:

    • Groovy 不是严格的超集吗?如果是这样,我想你可以告诉你的客户它正在使用 Java,他们不会更聪明。
    • 啊,我错了。 java 文件几乎总是有效的 groovy 代码,但它不是严格的超集。
    【解决方案7】:

    遍历文件夹中的文件列表很容易。有人提到可以从 Java 调用 Java 编译器(如果您重新分发 JDK,我认为这是需要检查其合法性的一点!!)这就是战斗的主要部分。

    您的脑海中似乎有一个固定的模型,其中仅从文件夹中提取满足特定接口的文件。我认为这是您的方法需要付出一点的地方。执行此操作的明智方法 (IMO) 是编译该文件夹中的 all 文件,然后将它们的类隐藏在某个地方,您可以加载并反映它们,然后确定它们中的哪些“执行”界面,哪些没有。那些不执行的代码将被不必要地加载到您的 JVM 中,但除非它故意非常浪费空间,否则您不执行的代码不会损害您的程序。

    在确定了哪些类做可计算的事情后,您可以将这些类(或其实例)存储在一个 Collection 中,并对它们做任何您喜欢的事情。您只需忽略其他的。

    【讨论】:

      【解决方案8】:

      您可以使用 BeanShell。这个库很小,不需要 JDK。它用于许多 IDE 和 Web 服务器。最新版本似乎支持您从类路径加载 .java 文件。 (仍处于测试阶段)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-28
        • 2021-04-25
        • 2010-10-13
        • 1970-01-01
        • 2017-05-28
        • 1970-01-01
        • 2010-09-17
        相关资源
        最近更新 更多