而不是使用DLL本身,它似乎是想要的是某种插件体系结构。
为什么我不推荐使用DLL,除非必要,否则将Java代码与本机代码连接将需要使用Java Native Interface(JNI),这可能需要比纯Java解决方案更多的努力。
一个相对简单的方法是使用Java的reflection功能。
从给出的信息,我可能会沿着以下的走行:
- 定义输出格式的接口。
- 创建一个实现该接口的Java类。
- 从classpath获得该课程。
- 使用反射动态加载类。 (使用
Class.newInstance
方法可以由ClassLoader
加载class
文件实例化对象。)
通过这些步骤,将有可能实现一个简单的插件,它不会需要完全重建时,新格式的支持是必须的。
第1步:定义接口
比方说,我们最终喜欢的界面如下:
public interface Outputter {
public void write(Data d);
}
第2步:实现类
然后,我们将制作一个实施课程。
public class TextOutputter {
public void write(Data d) {
// ... output data to text
}
}
然后,编译上述,我们将用class
文件名为TextOutputter.class
结束。
第3步:从类路径
类时运行的主要应用,我们需要有在classpath以上TextOutputter.class
。通常,人们会告诉JVM需要考虑的类路径列表,并且应包含上述class
文件。
一旦完成,我们应该能够使用反射来加载上述类。
第4步:使用动态反射
现在加载类,当我们真正想加载上面的类,我们会做类似如下:
// Note: We load the class by specifying the fully-qualified class name!
Class<?> clazz = Class.forName("TextOutputter");
// Then, we instantiate the class.
// Note that the following method will call the no-argument constructor.
Outputter outputter = clazz.newInstance();
// Now, we can give data to the TextOutputter object that we loaded dynamically.
outputter.write(...);
的Class.forName
方法用于尝试从默认的ClassLoader
中找到TextOutputter
类。一旦我们获得该类作为Class
表示,我们就可以实例化该类的一个对象。
实例化对象可以通过使用Class.newInstance
方法执行。如果应该使用除无参数构造函数以外的其他内容,则必须继续获取该类的Constructor
,以便从那里实例化对象。
通过反射将对象实例化,然后将其放入Outputter
变量中,因此可以在TextOutputter
上调用write
方法。
添加更多的格式将产生上述过程,但改变的完全合格的类名称(例如,对于String
,所述FQCN是java.lang.String
)是所有需要加载了一个不同的类。
简而言之,这就是它会采取动态加载class
文件和应用程序中使用它。
(正如一个侧面说明,我其实没有编译上面的代码,所以有可能是在这里和那里的一些错误,但我希望我能说明这个过程将需要。)
是的,除非你想要使用需要JNI和动态本地库的类(对于用作POJO的高性能或特定的外部库)。由于您无法使用标准的类加载器重新加载DLL绑定类,因此您需要在此情况下对其进行子类化。 – dweeves 2011-01-05 17:44:44
另外需要注意的是,在更新版本的java中,您可以使用服务提供者机制(java.util.ServiceProvider)来标准化插件jar的插件实现的加载。 – jtahlborn 2011-01-05 17:47:10
@dweeves:你不需要继承classloader。你只需要使用一个单独的类加载器,并在你想卸载dll时放弃它。 – jtahlborn 2011-01-05 17:48:33