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

77

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

我知道SWT就是这种情况。 swt.jar 包含dll文件,但我不知道如何做这件事以及如何使其正常工作。

2个回答

90

只需要将DLL文件放入jar包中的任何位置。但是,请记住,在使用DLL之前,您需要实际从JAR中提取这些文件并将它们转储到硬盘上的某个位置,否则您将无法加载这些文件。

所以基本上,我为客户做了一个JNI项目,其中我将在war中使用这样的jar包。但是,在运行任何本地方法之前,我会将DLL作为资源获取并将其写入临时目录中的磁盘。然后我会运行常规初始化代码,我的DLL设置为我刚刚写DLL的相同位置

哦,以防万一:将DLL或任何其他文件打包到jar中没有什么特别的。它就像将东西打包到zip中一样简单

下面是我找到的一些代码

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
}

8
在采用这种方法时,请注意清理临时文件。如果每次重复使用相同的路径,请考虑如果多个应用程序使用您的JAR文件会发生什么情况(如果另一个应用程序已经锁定了临时文件,则其中一个应用程序将失败)。只需小心 - 有时将JAR和DLL文件分别部署会更加容易。 - Kevin Day
9
需要记住的一件事是:我正在使用依赖于其他DLL的JNI DLL。我将所有DLL都包含在一个jar文件中,并使用上面的代码进行解压缩。但是,我遇到了java.lang.UnsatisfiedLinkError异常,显示“找不到依赖库”。问题在于,您必须按照依赖的DLL的顺序调用System.load()。这样可以先加载依赖的DLL。 - Liron Yahdav
1
你能告诉我在loadLib()方法中,你提到了ACWrapper.class。你能告诉我这是什么类吗?我是指与你的项目相关的类。因为我需要知道如何从war中提取DLL文件。 - Milind Jindal
1
只需在与 DLL 相同的目录中创建一个类。您使用的类决定了 getResourceAsStream 在哪里查找资源。 - Joanis
1
在你使用DLL之前,你需要从JAR文件中提取它们并将其转储到硬盘的某个位置,否则你将无法加载这些DLL。为什么呢?也许我的问题应该是一个单独的SO问题? - birgersp
显示剩余4条评论

7

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


32
提示他人:许可证为GPLv3,这在很大程度上限制了适用范围。 - Trevor Robinson
5
请注意:这个类加载器会将所有嵌套的 JAR 包解压到一个临时目录中,所以它的工作方式类似于第一个答案。只有在需要的情况下,本机库才会被解压缩。 - drzymala
2
商业许可证可用。 - drzymala

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接