如何制作包含DLL文件的JAR文件?


72

我购买了一个第三方Java库,其中包括一个JAR文件和两个DLL文件。我编写了自己的Java程序,该程序调用了第三方JAR文件。现在,我的问题是如何将我的所有代码打包到一个包含所有代码以及第三方JAR和DLL的JAR文件中?

我知道SWT就是这种情况。在swt.jar包括DLL文件,但我不知道如何做到这一点,以及如何使其正常工作。

Answers:


84

只需将其包装在罐子中的任何位置即可。不过,您必须记住一件事-在使用DLL之前,您需要先从JAR中提取这些DLL,然后将其转储到硬盘上的某个位置,否则您将无法加载这些DLL。

所以基本上-我为客户端做了JNI项目,我将在战争中使用这种打包的jar。但是-在运行任何本机方法之前,我将获得DLL作为资源并将其写入光盘到temp目录中。然后,我将运行常规的初始化代码,在该代码中,我的DLL设置为我刚刚写DLL到的位置

哦,以防万一:将dll或任何其他文件包装到jar中并没有什么特别的。就像把东西包装成拉链

这是我刚挖出的一些代码

public class Foo {
private static final String LIB_BIN = "/lib-bin/";
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private final static String ACWRAPPER = "acwrapper";
private final static String AAMAPI = "aamapi51";
private final static String LIBEAU = "libeay32";

static {
    logger.info("Loading DLL");
    try {
        System.loadLibrary(ACWRAPPER);
        logger.info("DLL is loaded from memory");
    } catch (UnsatisfiedLinkError e) {
        loadFromJar();
    }
}

/**
 * When packaged into JAR extracts DLLs, places these into
 */
private static void loadFromJar() {
    // we need to put both DLLs to temp dir
    String path = "AC_" + new Date().getTime();
    loadLib(path, ACWRAPPER);
    loadLib(path, AAMAPI);
    loadLib(path, LIBEAU);
}

/**
 * Puts library to temp dir and loads to memory
 */
private static void loadLib(String path, String name) {
    name = name + ".dll";
    try {
        // have to use a stream
        InputStream in = ACWrapper.class.getResourceAsStream(LIB_BIN + name);
        // always write to different location
        File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
        logger.info("Writing dll to: " + fileOut.getAbsolutePath());
        OutputStream out = FileUtils.openOutputStream(fileOut);
        IOUtils.copy(in, out);
        in.close();
        out.close();
        System.load(fileOut.toString());
    } catch (Exception e) {
        throw new ACCoreException("Failed to load required DLL", e);
    }
}
    // blah-blah - more stuff
}

7
使用这种方法时要小心-确保清除临时文件。如果您每次都重复使用同一路径,请考虑如果多个应用程序使用您的JAR会发生什么(如果另一个应用程序已经对临时文件进行了锁定,则一个应用程序将失败)。请小心-有时分别部署JAR和DLL更容易。
凯文·

8
要记住的一件事:我正在使用依赖于其他DLL的JNI DLL。我将所有DLL包含在一个jar中,并使用上面的代码来解压缩。但是我收到了java.lang.UnsatisfiedLinkError异常,说“找不到依赖库”。问题是您必须在DLL上调用System.load()才能先加载相关的DLL。
Liron Yahdav

1
您能告诉我loadLib()方法吗?您已经提到ACWrapper.class。你能告诉我这是什么课吗?我是说与您的项目有关?因为我需要知道如何从战争中提取DLL。
Milind Jindal

1
与DLL位于同一目录中的只是一个类。您使用的类确定在哪里getResourceAsStream检查资源。
乔妮丝

1
一种更可靠的加载方法是System.load(fileOut.getAbsolutePath());。
林德伯格

7

使用http://www.jdotsoft.com/JarClassLoader.php可以从具有无限嵌套的另一个JAR加载DLL和JAR。例如,DLL可能位于另一个根JAR中的JAR中。所有DLL和JAR都像在类路径或库路径中一样加载。


30
其他注意事项:许可证是GPLv3,这大大限制了其适用性。
Trevor Robinson

5
另请注意:此类加载器将所有嵌套的jar打包解压缩到一个临时目录中。因此,它的工作原理类似于第一个答案。仅在需要时才解压缩本机库。
drzymala

2
提供商业许可证。
drzymala
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.