2011-01-05 49 views
3

我目前正在研究一个Java项目,我有一组数据,我希望以多种自定义格式输出。我为每种格式都有一个类,它接收原始数据并相应地转换它。但是,首先我只实现了其中两种或三种格式,但希望在日后添加更多格式,而无需重新编译应用程序。动态Java程序的DLL?

我的想法是为每个格式类创建一个DLL,并让我的应用程序将要转换的数据传递给每个这些类。这样,我可以稍后创建一个DLL,让我的主应用程序访问它。 (我很乐意听取任何替代方法,因为有人在C++/C#中完成此操作之前感觉像是逻辑解决方案,但它可能不适用于Java)

我的问题是我绝对不知道如何做到这一点 - 在C++/C#中,我可以用几行代码写这个,但我不确定它如何与Java一起工作。冒着问一个非常含糊的问题的风险,我该怎么做?

答案是非常感谢和饼干和茶将提供。 :)

由于提前, 中号

编辑:对不起,我想补充:我也不清楚如何创建DLL,它必须是在Java中为这个项目,首先读取。谢谢。 :)

回答

5

而不是使用DLL本身,它似乎是想要的是某种插件体系结构。

为什么我不推荐使用DLL,除非必要,否则将Java代码与本机代码连接将需要使用Java Native Interface(JNI),这可能需要比纯Java解决方案更多的努力。

一个相对简单的方法是使用Java的reflection功能。

从给出的信息,我可能会沿着以下的走行:

  1. 定义输出格式的接口。
  2. 创建一个实现该接口的Java类。
  3. classpath获得该课程。
  4. 使用反射动态加载类。 (使用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文件和应用程序中使用它。

(正如一个侧面说明,我其实没有编译上面的代码,所以有可能是在这里和那里的一些错误,但我希望我能说明这个过程将需要。)

+0

是的,除非你想要使用需要JNI和动态本地库的类(对于用作POJO的高性能或特定的外部库)。由于您无法使用标准的类加载器重新加载DLL绑定类,因此您需要在此情况下对其进行子类化。 – dweeves 2011-01-05 17:44:44

+0

另外需要注意的是,在更新版本的java中,您可以使用服务提供者机制(java.util.ServiceProvider)来标准化插件jar的插件实现的加载。 – jtahlborn 2011-01-05 17:47:10

+0

@dweeves:你不需要继承classloader。你只需要使用一个单独的类加载器,并在你想卸载dll时放弃它。 – jtahlborn 2011-01-05 17:48:33

1

如果您想在java中使用编写本地代码(编译为DLL),那么您需要查看Java Native Interface (JNI)

你可以使用 System.loadLibrary(String libName)(如果你知道库名称和库路径设置)

更新或System.load(String filename)(库文件名)在Java加载库(DLL)。

1

您可以随时使用System.loadLibrary()加载新的DLL。但是你可能需要加载一个java类来绑定它。

您可能会发现使用OSGi容器作为这是很有帮助的支持负载和模块(包括共享库)的卸载

我会建议使用karaf与iPOJO,但也有许多人。

2

我做了这样的事情。 我创建了一个基于开放式Java的插件体系结构POJO,甚至可以在更新插件类的基础上重新加载。 JNI是处理本机代码的接口。 唯一的技术部分是重写一个在运行时动态重新加载DLL的类加载器。 但是,如果您只做“离线”更新,则不需要这样的事情。

1

我想你可以忽略JNI路径。我的印象是你使用dll这个术语缺乏更好的单词,你并不需要一个dll。

你可以在Java中做同样的事情,但你会把你的过滤器放入jar文件而不是dll。

  1. 定义文件格式过滤器的接口来实现
  2. 将各实施成jar,在一个特定的文件夹(如“过滤器”)
  3. 在应用中的一个点,重复的文件夹上,生成类加载器的罐子
  4. 使用反射来找到你的接口的所有实现,并创建一个类为每个
  5. 调用的方法做他们的工作

基本上就是这样。

1

Java SE 6中引入了ServiceLoader类: ​​

如果你想有一个正确的模块化方法考虑NetBeans平台(尤其是如果它是一个桌面应用程序)或OSGi的。