前言
場景:某些功能已有C語言實現,現有Java業務系統需要引入。
這種情況下,如果用Java重寫一遍可能更加費時費力,不如將此C語言功能編譯為一個系統庫,供Java調用。
1 引入JNA
pom文件添加依賴
<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.5.2</version>
</dependency>
2 Windows系統調用dll
設dll文件名為libtest.dll
,將其放置於此Java文件同文件夾下或項目resources目錄。
調用demo代碼
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JavaCallDllDemo {
public interface CLibrary extends Library {
// DLL文件默認路徑為項目根目錄,若DLL文件存放在項目外,請使用絕對路徑
CLibrary INSTANCE = (CLibrary) Native.load("libtest", CLibrary.class);
// 聲明將要調用的DLL中的方法(可以是多個方法)
int add(int a, int b);
}
public static void main(String[] args) {
int result = JavaCallDllDemo.CLibrary.INSTANCE.add(200, 300);
System.out.println("result: " + result);
}
}
注意這里代碼加載庫文件不需要帶dll
后綴
3 Linux系統調用so
設so文件名為libtest.so
,將其放置於/usr/lib下,或者自定義目錄,如/usr/local/lib
。
自定義目錄需要額外將其添加到環境變量
vim /etc/profile
在末尾添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
刷新環境變量,使改動生效
source /etc/profile
調用demo代碼
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JavaCallSoDemo {
public interface CLibrary extends Library {
// SO文件默認路徑為/usr/lib
CLibrary INSTANCE = (CLibrary) Native.load("test", CLibrary.class);
// 聲明將要調用的so中的方法(可以是多個方法)
int add(int a, int b);
}
public static void main(String[] args) {
int result = JavaCallSoDemo.CLibrary.INSTANCE.add(200, 300);
System.out.println("result: " + result);
}
}
注意這里代碼加載庫文件不需要帶lib
前綴和so
后綴
4 兼容Windows和Linux調用
由上可以將代碼整合一下,自動判斷環境以決定調用名
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class JavaCallDllSoDemo {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.load(Platform.isWindows() ? "libtest" : "test", CLibrary.class);
int add(int a, int b);
}
public static void main(String[] args) {
int result = JavaCallDllSoDemo.CLibrary.INSTANCE.add(200, 300);
System.out.println("result: " + result);
}
}
5 附,生成簡單dll/so
下面簡要說明如何自己生成dll/so,以供測試。
這里使用工具為Dev C++。
5.1 Windows下生成dll
自行下載Dev C++, 打開,點擊文件 -> 新建 -> 項目
,選擇dll
,C項目
,名稱輸入libtest
,確定。
之后會生成一個dllmain.c文件和dll.h文件。
修改內容並保存:
dllmain.c文件
#include "dll.h"
DLLIMPORT int add(int a, int b)
{
return a+b;
}
dll.h文件
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
#define DLLIMPORT __declspec(dllexport)
#else
#define DLLIMPORT __declspec(dllimport)
#endif
DLLIMPORT int add(int a, int b);
#endif
如此,就聲明了一個方法,方法兩個int參數,返回兩數之和。
之后點擊運行 -> 編譯
,會在項目目錄下生成libtest.dll
文件。
5.2 Linux下生成so
將以上dllmain.c和dll.h文件稍作修改:
dllmain.c文件
#include "dll.h"
int add(int a, int b)
{
return a+b;
}
dll.h文件
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
#define DLLIMPORT __declspec(dllexport)
#else
#define DLLIMPORT __declspec(dllimport)
#endif
int add(int a, int b);
#endif
將兩個文件復制到linux中,執行gcc命令
gcc dllmain.c -fPIC -shared -o libtest.so
即在當前目錄下生成libtest.so
文件。