首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

JNI 實戰:System.loadLibrary 找不到 DLL 的路徑問題排查與解決

     編輯:J2ME

現象描述

System.loadLibrary("EasySpell"); // 拋出 UnsatisfiedLinkError

DLL 放置位置嘗試過:system32、類包目錄、class 同級目錄。CMD 下直接運行類測試通過,但 Eclipse 啟動 Tomcat 時失敗。

根因分析

System.loadLibrary 搜尋路徑順序:

  1. java.library.path 系統屬性指定的目錄列表
  2. 系統環境變量 PATH (Windows) / LD_LIBRARY_PATH (Linux)
  3. 當前進程工作目錄

關鍵差異:

  • CMD 下啟動 JVM,工作目錄通常為類所在目錄,DLL 在同級 → 找到。
  • Eclipse 啟動 Tomcat,工作目錄為 Tomcat 安裝目錄(如 bin),DLL 不在 java.library.path 或 PATH 覆蓋範圍 → 找不到。

解決方案(按推薦順序)

方案一:啟動參數指定 java.library.path(最標準)

在 Eclipse → Run Configurations → Arguments → VM arguments 添加:

-Djava.library.path=/absolute/path/to/dll/dir

Tomcat 啟動腳本 catalina.bat/sh 同理配置 CATALINA_OPTS。

方案二:將 DLL 目錄加入系統 PATH

  • Windows:系統屬性 → 環境變量 → Path 新增 DLL 所在目錄絕對路徑,重啟 Eclipse/Tomcat 生效。
  • Linux:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/dll。

方案三:代碼中動態修改 java.library.path(不推薦,JDK 9+ 受限)

System.setProperty("java.library.path", "/path/to/dll");
// 需配合反射刷新 sys_paths 字段(JDK 8 有效,JDK 9+ 模組化後失效)
Field sysPaths = ClassLoader.class.getDeclaredField("sys_paths");
sysPaths.setAccessible(true);
sysPaths.set(null, null);

方案四:使用 System.load(String absolutePath) 絕對路徑加載

String dllPath = System.getProperty("user.dir") + "/native/EasySpell.dll";
System.load(dllPath); // 需確保運行時路徑正確

方案五:打包進 JAR,運行時釋放到臨時目錄加載(跨平台發布首選)

InputStream in = getClass().getResourceAsStream("/native/EasySpell.dll");
File tmp = File.createTempFile("EasySpell", ".dll");
Files.copy(in, tmp.toPath(), StandardCopyOption.REPLACE_EXISTING);
tmp.deleteOnExit();
System.load(tmp.getAbsolutePath());

排查清單

  1. DLL 是 32/64 位與 JVM 架構匹配?
  2. DLL 依賴的其他動態庫(VC++ Runtime 等)是否存在?
  3. Tomcat 是否以服務模式運行(服務帳號環境變量不同)?
  4. 多 webapp 共用同一 DLL 是否衝突(建議放共享類加載器目錄)?

總結

核心原則:**構建/部署階段確定 DLL 絕對路徑,通過 java.library.path 或系統 PATH 註冊,避免依賴不穩定的工作目錄**。生產環境建議採用方案五(JAR 內嵌 + 臨時釋放),實現「單一 JAR/War 部署,無外部依賴」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved