jna使用之(三)java调用动态库dll/so-设计自己的加载动态库框架
程序员文章站
2022-05-28 12:02:33
...
-
一、加载的前提准备
加载动态库之前需要明白一下几个避坑点:
- 动态库本身使用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));
}
}
上一篇: 中文显示
下一篇: Sublime配置java运行环境