java - 使用 RXTX 部署独立应用程序

标签 java maven java-native-interface rxtx

我有一个现有的应用程序,通常通过 TCP 与其目标进行通信,但新要求规定也可以通过串行 COM 端口建立连接。

该应用程序本身是完全独立的,即它是一个 jar 文件,最终用户可以将其复制到可能需要的位置,然后双击启动。

看起来 RXTX 打破了这个模型,因为它需要额外的DLLSO native 插件包含在库路径中;如果无法使用 native Java 与串行端口进行通信,我如何打包我的应用程序(使用 ,aven),以便 RXTX 在运行时可用,只需双击 Jar 文件即可。

java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path: [__CLASSPATH__] thrown while loading gnu.io.RXTXCommDriver

最佳答案

您需要将库打包到 jar 文件中,然后提取它,将其写为文件,然后加载它(省略 import 语句和异常/错误处理):

public class YourClass {
    static {
        // path to and base name of the library in the jar file
        String libResourcePath = "path/to/library/yourLib.";

        // assume Linux
        String extension = "so";

        // Check for Windows
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("win"))
            extension = "dll";

        libResourcePath += extension;

        // find the library in the jar file
        InputStream is = ClassLoader.getSystemResourceAsStream( libResourcePath );

        // create a temp file for the library
        // (and we need the File object later so don't chain the calls)
        File libraryFile = File.getTempFile("libName", extension);

        // need a separate OutputStream object so we can
        // explicitly close() it - can cause problems loading
        // the library later if we don't do that
        FileOutputStream fos = new FileOutputStream(libraryFile);

        // assume Java 9
        is.transferTo(fos);

        // don't forget these - especially the OutputStream
        is.close();
        fos.close();

        libraryFile.setExecutable(true);
        libraryFile.deleteOnExit();

        // use 'load()' and not 'loadLibrary()' as the
        // file probably doesn't fit the required naming
        // scheme to use 'loadLibrary()'
        System.load(libraryFile.getCanonicalPath());
    }

    ...
}

请注意,您需要为您支持的每个操作系统和架构添加库的版本。这包括 32 位和 64 位版本,因为很可能在 64 位操作系统上运行 32 位 JVM。

您可以使用 os.arch 系统属性来确定您是否在 64 位 JVM 中运行。如果该属性中包含字符串 "64",则您正在 64 位 JVM 中运行。假设它是 32 位 JVM 是相当安全的,否则:

if (System.getProperty("os.arch").contains("64"))
    // 64-bit JVM code
else
    // 32-bit JVM code

如果您要自定义类加载器,您可能还必须使用 YourClass.class.getClassLoader().getResourceAsStream()

注意操作系统和 CPU 兼容性。您需要编译您的库,以便它们在较旧的操作系统版本和较旧的 CPU 上运行。如果您在新 CPU 上构建 Centos 7,那么尝试在 Centos 6 或更旧的 CPU 上运行的人将会遇到问题。您不希望您的产品因用户的库收到非法指令的 SIGILL 信号而崩溃。我建议在可以控制构建环境的虚拟机上构建库 - 使用较旧的 CPU 型号创建虚拟机并在其上安装旧的操作系统版本。

您还需要留意使用 noexec 挂载 /tmp 的 Linux 系统。该设置或某些 SE Linux 设置可能会导致共享对象加载失败。

关于java - 使用 RXTX 部署独立应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57904922/

相关文章:

java - 在不失去通用性的情况下包装逆变函数接口(interface)

java - 如何检测我的测试是否在 Jenkins 环境中运行?

ubuntu - 在 Ubuntu 14.04 : 上安装 SCIP JNI(Java native 接口(interface))

java - Vaadin + Spring Boot 生产模式构建时出现运行时错误 : Failed to determine 'npm' tool

maven - 在没有程序集插件的情况下将 maven tar.gz Artifact 部署为构建输出

android - getArrayLength() 返回一个巨大的数字......

java - JNI 无法在 NetBeans 上检测到 __int64

java - 如何在 @test.enabled 属性中给出运行时值

Java性能谜题: wrapper classes faster than primitive types?

java - 远程访问hbase