在 Java 開發中,有時需要調用本地 C/C++ 編寫的 DLL 動態鏈接庫。雖然 JNI(Java Native Interface)是官方標準,但編寫 JNI 代碼繁瑣且易出錯。開源項目 JNative 提供了一種更輕量、無需編寫 C++ 代碼即可直接調用 DLL 的方案。本文將詳細介紹 JNative 的下載、配置、核心 API 使用,以及兩種 DLL 載入策略的實戰代碼。
訪問官網 jnative.sourceforge.net 下載最新版本(本文以 1.3.2 為例)。
C:\Windows\System32 目錄(或項目啟動路徑)。/usr/lib)。lib 目錄或複製到 JDK/jre/lib/ext 目錄下,JVM 會自動加載。TestAppSvr.dll假設 DLL 導出一個函數:int TestConnect(char* ip, int port, int compress),返回 1 表示連接成功,0 表示失敗。
AppSvrTestConnectpackage com.tvjody;
import java.io.*;
import org.xvolks.jnative.JNative;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
public class AppSvrTestConnect {
/**
* 核心私有方法:通過 JNative 直接調用 DLL 導出函數
*/
private static int testConnect(String ip, int port, int compress)
throws NativeException, IllegalAccessException {
JNative nativeCall = null;
try {
// 參數:DLL 文件名(需在系統路徑或 java.library.path 中)、導出函數名
nativeCall = new JNative("TestAppSvr.dll", "TestConnect");
nativeCall.setRetVal(Type.INT); // 設置返回值類型
int idx = 0;
nativeCall.setParameter(idx++, Type.STRING, ip); // 參數1:IP 字符串
nativeCall.setParameter(idx++, Type.INT, port); // 參數2:端口 int
nativeCall.setParameter(idx++, Type.INT, compress); // 參數3:壓縮標誌 int
nativeCall.invoke(); // 執行調用
return Integer.parseInt(nativeCall.getRetVal());
} finally {
if (nativeCall != null) nativeCall.dispose(); // 釋放本地資源
}
}
/**
* 方式一:指定 DLL 絕對路徑載入(適合開發調試,DLL 與項目同目錄)
*/
public static int testConnectFromDllPath(String dllDir, String ip, int port, int compress)
throws NativeException, IllegalAccessException {
String fullPath = dllDir + "TestAppSvr.dll";
System.load(fullPath); // 載入指定路徑的 DLL
return testConnect(ip, port, compress);
}
/**
* 方式二:依賴系統類加載器載入(DLL 已放入 JRE/bin 或 Tomcat/bin)
*/
public static int testConnectFromSystemPath(String ip, int port, int compress)
throws NativeException, IllegalAccessException {
System.loadLibrary("TestAppSvr"); // 僅需 DLL 文件名(無後綴)
return testConnect(ip, port, compress);
}
}
Demopublic class Demo {
public int getInfo() throws NativeException, IllegalAccessException {
// 獲取當前類所在目錄(作為 DLL 目錄)
String path = getClass().getResource(File.separator).getPath();
if (path.startsWith("/")) path = path.substring(1); // Windows 路徑修正
String ip = "192.168.0.48";
int port = 221;
int compress = 1; // 1=啟用壓縮
// 方式一:傳入 DLL 目錄路徑
// int result = AppSvrTestConnect.testConnectFromDllPath(path, ip, port, compress);
// 方式二:DLL 已放入 JRE/bin,由類加載器自動發現
int result = AppSvrTestConnect.testConnectFromSystemPath(ip, port, compress);
if (result == 1) {
System.out.println("應用服務器可用。");
} else {
System.out.println("應用服務器不可用,請檢查 IP 和端口。");
}
return result;
}
}
| 方法 | 適用場景 | 路徑要求 |
|---|---|---|
System.load(path) | 指定絕對路徑載入 | 完整路徑含文件名,如 D:/libs/TestAppSvr.dll |
System.loadLibrary(name) | 依賴 java.library.path | 僅文件名(無後綴),DLL 需在系統路徑或 -Djava.library.path 指定目錄 |
TestAppSvr.dll 依賴其他 DLL(如 VC++ 運行庫),確保依賴項也在系統 PATH 中。UnsatisfiedLinkError。finally 塊調用 JNative.dispose(),避免本地內存洩漏。JNative 以極低的接入成本解決了 Java 調用本地 DLL 的需求,適合輕量級集成場景。生產環境建議將 DLL 放入固定目錄並配置 java.library.path,採用 System.loadLibrary 方式,便於部署與維護。若項目對性能、穩定性要求極高,或涉及複雜數據結構傳遞,仍建議使用標準 JNI 或 JNA(Java Native Access)框架。