【问题标题】:How to use implementation loaded with different Java classloader?如何使用不同 Java 类加载器加载的实现?
【发布时间】:2009-11-18 18:57:08
【问题描述】:

我正在编写一个库,允许人们使用插件框架(如果您熟悉的话,它是 JPF)来提供某些接口的实现。插件不存储在类路径中。该框架为每个插件提供了一个 ClassLoader,因此当请求接口“MyInterface”的名为“MyImpl”的实现时,我可以找到正确的插件,然后使用该插件的 ClassLoader 加载类,我可以从中创建一个实例如果我对构造函数有所了解。到目前为止一切顺利。

但是,现在我需要调用一个仅在该特定实现上可用的方法。所以,我可以尝试两种方法:

方法一:

// Makes sure that MyImpl has been loaded, using the custom classloader
Plugins.getClass(MyInterface.class, "MyImpl");
// This line will not compile because MyImpl is not available at build time
MyImpl foo = new MyImpl();
// If I could get this far, this line would work:
foo.methodOnlyInMyImpl();

方法二:

// This call will get an instance of MyImpl (already written and tested)
MyInterface foo = Plugins.getInstance(MyInterface.class, "MyImpl");
// Compiler error because there is no MyInterface.methodOnlyInMyImpl method.
foo.methodOnlyInMyImpl()

方法 1 是两者中更简洁的方法,因为它最类似于如果类是“正常”且无法通过插件访问时编写代码的方式。但是,两者都无法编译。

到目前为止我想出的选项:
A.使用方法2,但是使用反射来做methodOnlyInMyImpl方法调用(请不要!)
B. 将插件类放在构建路径中,然后使用方法 1,它会编译。 (我目前最喜欢的)
C. B+ 安装插件时,将类文件复制到类路径中的另一个目录,以便系统类加载器可以加载它们(导致其他问题)

所以,我的问题是:

  1. 我是否错过了另一个更好的想法?
  2. 如果我做 B,我会在运行时遇到问题吗?毕竟,使用 MyImpl 的类可能已经使用系统类加载器加载了。那么,一旦它看到MyImpl foo,它会不会尝试使用系统类加载器加载 MyImpl,这会失败(即使 Plugins.newInstance 调用会提供 MyImpl 的实例)?

【问题讨论】:

    标签: java classloader jpf


    【解决方案1】:

    首先,当您需要针对实际实现进行实现时,您从插件机制中获得了什么优势?该插件应该实现一个接口,您可以通过该接口使用该实现。

    我不熟悉 JPF,但是当不同的类加载器加载时,java 类永远不会兼容。但是有两种可能的方式:

    1. 接口在你的类加载器中,插件类加载器有你的类加载器作为父类,所以它的接口和你的一样。当方法在接口中声明时,代码 2 应该可以使用它。

    2. 您可以使用序列化。这是一种在独立类加载器之间传输数据对象更有用的有限方式。我需要使用它在两个 webapps 之间使用请求参数进行跨上下文调度。

    【讨论】:

    • 一个说明优势的例子:我有接口 X 和 Y。有一个 X.getY() 方法返回一个 Y。我有四个插件提供 X 实现 Xa 和 Xb 和 Y 实现Yc 和 Yd。现在,Xa 和 Xb 都需要在内部使用实现 Yc,所以这就是我需要具体实现的地方。应用程序只能与 Xs 和 Ys 交互,但插件需要特定的实现。 JPF 帮助处理插件依赖关系。
    • +1 - OP 试图忽略使用接口所暗示的合同。如果插件是唯一关心实现类的插件,那么他/她将必须提供对实现类的编译时访问,使用强制转换并处理可能的 ClassCastException。
    • 不幸的是,我无法预料到所有的接口。序列化 (Arne)、运行时强制转换 (kdgregory) 和 TransLoader (Carl) 都要求类在当前类加载器中以某种方式可用,但在我的情况下并非如此——它归结为使用反射或对运行时提出要求包含插件目录的类路径。我选择了后者。接受这个答案是因为关键短语“java 类在由不同的类加载器加载时永远不兼容”。谢谢,如果我有代表,我会 +1。
    【解决方案2】:

    在上一个问题中提到了一个名为 TransLoader 的库。这是源的 URL:http://code.google.com/p/transloader/

    【讨论】:

    • 这很有帮助,如果我的要求不同,也会有所帮助。谢谢。如果我有代表,我会 +1。
    • +1 back atcha,很高兴我有代表。很抱歉,我无法更仔细地辨别并满足您的要求。
    猜你喜欢
    • 2018-03-14
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 2012-05-21
    • 2016-11-20
    • 2012-07-30
    • 2013-08-15
    • 1970-01-01
    相关资源
    最近更新 更多