使用 RXTX 部署自包含应用程序
Deploying a self-contained application with RXTX
我有一个现有的应用程序,它通常通过 TCP 与其目标进行通信,但是新的要求规定也可以通过串行 COM 端口建立连接。
目前的应用程序是完全独立的,因为它是一个单一的 jar 文件,最终用户可以将其复制到可能需要的地方,然后双击启动。
RXTX 似乎打破了这个模型,因为它需要额外的 DLL 或 SO 本地插件包含在库路径中;如果无法使用本机 Java 与串行端口通信,我如何打包我的应用程序(使用 ,aven)以便 RXTX 在运行时可用,只需双击 Jar 文件即可。
java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path: [__CLASSPATH__] thrown while loading gnu.io.RXTXCommDriver
您需要将库打包到您的 jar 文件中,然后将其解压缩,将其作为文件写入,然后加载它(省略 import
语句和 exception/error 处理):
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());
}
...
}
请注意,您需要为每个 OS 和您支持的体系结构添加您的库版本。这包括 32 位和 64 位版本,因为很可能 运行 64 位 OS.
上的 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
如果您要自定义 class 加载器,您可能还必须使用 YourClass.class.getClassLoader().getResourceAsStream()
。
注意 OS 和 CPU 的兼容性。您需要编译您的库,以便它们 运行 在旧的 OS 版本和旧的 CPU 上。如果您在新的 CPU 上构建 Centos 7,那么尝试在 Centos 6 或更旧的 CPU 上 运行 的人将会遇到问题。您不希望您的产品在用户身上崩溃,因为您的库收到了非法指令的 SIGILL
信号。我建议在 VM 上构建库,您可以在其中控制构建环境 - 使用旧的 CPU 模型创建 VM 并在其上安装旧的 OS 版本。
您还需要注意挂载 /tmp
和 noexec
的 Linux 系统。该设置或某些 SE Linux 设置可能会导致共享对象加载失败。
我有一个现有的应用程序,它通常通过 TCP 与其目标进行通信,但是新的要求规定也可以通过串行 COM 端口建立连接。
目前的应用程序是完全独立的,因为它是一个单一的 jar 文件,最终用户可以将其复制到可能需要的地方,然后双击启动。
RXTX 似乎打破了这个模型,因为它需要额外的 DLL 或 SO 本地插件包含在库路径中;如果无法使用本机 Java 与串行端口通信,我如何打包我的应用程序(使用 ,aven)以便 RXTX 在运行时可用,只需双击 Jar 文件即可。
java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path: [__CLASSPATH__] thrown while loading gnu.io.RXTXCommDriver
您需要将库打包到您的 jar 文件中,然后将其解压缩,将其作为文件写入,然后加载它(省略 import
语句和 exception/error 处理):
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());
}
...
}
请注意,您需要为每个 OS 和您支持的体系结构添加您的库版本。这包括 32 位和 64 位版本,因为很可能 运行 64 位 OS.
上的 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
如果您要自定义 class 加载器,您可能还必须使用 YourClass.class.getClassLoader().getResourceAsStream()
。
注意 OS 和 CPU 的兼容性。您需要编译您的库,以便它们 运行 在旧的 OS 版本和旧的 CPU 上。如果您在新的 CPU 上构建 Centos 7,那么尝试在 Centos 6 或更旧的 CPU 上 运行 的人将会遇到问题。您不希望您的产品在用户身上崩溃,因为您的库收到了非法指令的 SIGILL
信号。我建议在 VM 上构建库,您可以在其中控制构建环境 - 使用旧的 CPU 模型创建 VM 并在其上安装旧的 OS 版本。
您还需要注意挂载 /tmp
和 noexec
的 Linux 系统。该设置或某些 SE Linux 设置可能会导致共享对象加载失败。