-
一、加載的前提準備
加載動態庫之前需要明白一下幾個避坑點:
- 動態庫本身使用32位編譯器編譯,則只能在32操作系統上加載成功;同理,若動態庫本身爲64位編譯器編譯,則只能在64位操作系統上加載成功;
- 動態庫本身所需的一級依賴必須在本機上具有,不缺失,即:不缺少依賴;
- 若在windows上加載,所需要加載動態庫依賴的第三方動態庫中缺少系統api,如api-ms-win-core-xxx.dll這些庫,可不用理會,不影響加載,但運行時可根據接口使用情況進行判斷是否需要解決缺失依賴;
- 在使用Native.load(String name, Class<T> interfaceClass)加載動態庫時,name變量不需要加.so或者.dll後綴,且若是linux下加載.so動態庫,lib前綴也省略,例如需要加載libCTest.so這個庫,則name=CTest即可。(原因是源碼內部根據操作系統類型已自動幫你添加lib前綴,自動填充了.so、.dll後綴)
-
二、依賴解決方式
依賴的解決有兩種:
- 將依賴拷貝至系統環境bin目錄下並註冊,具體的位置以windows舉例,32位拷貝至C:\Windows\System32下,64位拷貝至C:\Windows\SysWOW64\downlevel。(作參考,可谷歌,未實踐此方法);
- 將依賴拷貝至動態庫同級目錄下。(本文采用此方式)
查看依賴的工具可參考之前的文章:jna使用之(一)java調用動態庫dll/so-知識準備
-
三、jna加載動態庫路徑問題
jna加載動態庫具有多種方式,主要有以下三種:
(1).依賴庫在項目的\target\classes下,即,建立工程時,將依賴庫拷貝至在maven工程的src/main/resources;
(2).在maven工程的src/main/resources下建立系統文件夾名,並拷貝依賴至此,這裏只列舉linux和windows下文件夾名稱情況。
系統 | 位數 | 文件夾名 |
linux | 32 | linux-x86 |
64 | linux-x86-64 | |
windows | 32 | win32-x86 |
64 | win32-x86-64 |
(3).指定路徑模式,此方法需要配置動態庫根目錄,即"jna.library.path"環境變量(本文采用此方式)。
-
四、加載框架實現
我的加載框架實現主要由註解、接口、加載實現三個部分完成,在實際開發過程中,用戶只需要定義接口,並給接口上使用我們定義的註解,並拷貝動態庫之指定位置即可。具體代碼如下解析:
1.註解
linuxNam和windowsName指的是動態庫在兩個系統下的名稱,無前後綴。
package maoko.dllSolibLoad.lib.load;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* lib接口註解
*
* @author maoko
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LibLoad {
/**
* linux lib 名稱
*
* @return
*/
String linuxName() default "";
/**
* windows lib 名稱
*
* @return
*/
String windowsName() default "";
}
2.加載實現-JnaLibCall
使用到了反射掃描指定的LIBPACKAGE包下的接口,獲取定義註解LibLoad的動態庫名稱,進行加載;在函數setJnaLibPath()中預配置jna.library.path系統屬性,使jna在指定的地方進行加載.so/.dll。
package maoko.dllSolibLoad.lib.load;
import java.util.Set;
import com.sun.jna.Library;
import com.sun.jna.Native;
import maoko.common.ClassUtil;
import maoko.common.file.PathUtil;
import maoko.common.log.IWriteLog;
import maoko.common.log.Log4j2Writer;
import maoko.common.model.enm.EOsType;
import maoko.common.system.AppRunPathUitl;
import maoko.common.system.OSPlatformUtil;
/**
* lib動態庫調用方法:dll/so file mast have lib prefix
*
* @author fanpei
* @date 2019年5月22日下午4:49:43
*/
public class JnaLibCall {
private static final String LIBPACKAGE = "maoko.dllSolibLoad.lib.load.ifs";// 接口目錄,根據自己的動態庫接口所在包名進行修改
private static final IWriteLog log = new Log4j2Writer(JnaLibCall.class);
private static final String JNA_LIBRARY_PATH = "jna.library.path";
private static final String WINDOWS_LIB_PATH = "lib/windows";// local dll file location
private static final String LINUX_LIB_PATH = "lib/linux"; // local so file location
private static final String WINDOWS_SEPRATOR = ";";
private static final String LINUX_SEPRATOR = ":";
/**
* 加載
*
* @throws Exception
*/
public static void load() throws Exception {
EOsType ostype = OSPlatformUtil.getOSType();
setJnaLibPath(ostype);
// 加載dll
Set<Class<?>> clazzs = ClassUtil.getClasses(LIBPACKAGE, LibLoad.class, false);
if (clazzs != null) {
for (Class<?> dllclass : clazzs) {
Library libtmp = null;
@SuppressWarnings("unchecked")
Class<Library> clazzLib = (Class<Library>) dllclass;
LibLoad dllName = dllclass.getAnnotation(LibLoad.class);
try {
String libname = "";
if (EOsType.Linux == ostype) {
libname = dllName.linuxName();
} else// windows
{
libname = dllName.windowsName();
}
libtmp = Native.load(libname, clazzLib);
LibFactory.add(dllclass.getName(), libtmp);// 加入自定義庫工廠,用於後續根據名字調用
log.info("loading lib:{} sucessful", dllclass.getName());
} catch (Throwable e) {
log.warn("load lib file faied:{}", e);
}
}
log.info("loaded lib count:{}", LibFactory.totalLib());
}
}
/**
* 設置jna加載指定路徑
*
* @param ostype 系統類型
*/
private static void setJnaLibPath(EOsType ostype) {
String appPath = AppRunPathUitl.getAppRunPath();
String libRootPath = "";
String libPath = "";
// String nameEnd = "";
String seprator = "";
if (EOsType.Linux == ostype) {
libPath = LINUX_LIB_PATH;
// nameEnd = LINUX_DLL;
seprator = LINUX_SEPRATOR;
} else// windows
{
libPath = WINDOWS_LIB_PATH;
// nameEnd = WINDOWS_DLL;
seprator = WINDOWS_SEPRATOR;
}
libRootPath = PathUtil.combinePath(appPath, libPath);
String jnaPath = System.getProperty(JNA_LIBRARY_PATH);
System.err.println("jna.library.path:" + jnaPath);
if (jnaPath == null) {
jnaPath = libRootPath;
} else if (!jnaPath.contains(libRootPath))
jnaPath = jnaPath + seprator + libRootPath;
System.setProperty(JNA_LIBRARY_PATH, jnaPath);
System.setProperty("jna.debug_load", "true");//啓用jna調試日誌輸出
System.err.println("the latest jna.library.path:" + System.getProperty(JNA_LIBRARY_PATH));
}
}
代碼完整地址:https://download.csdn.net/download/fanpei_moukoy/11195072
https://github.com/maokofan/maoko.dllSoLibLoad