JNA加载存在多个依赖的so动态库

之前记录过在windows上加载单个ddl动态库(JNA简单使用(一)(java和c++互操作) - 浪迹天涯的派大星 - 博客园 (cnblogs.com)),这次记录一下在linux上调用存在多个依赖的so动态库。

1、背景

需要c++分片处理一种特殊格式的文件,Java接受分片数据后保存,采用JNA的方式调用c++动态库的方式实现。

2、Java代码

注:此处Java精简了逻辑,只为简单体现JNA调用c++的方式

2.1、Library接口代码

区别之一:load动态库时,windows上ddl不用写后缀,linux上so需要写后缀

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
public interface SlicerLibrary extends Library {
SlicerLibrary LIBRARY = Native.load("libEnv.so", SlicerLibrary.class);
/**
* 初始化环境
*
* @return 是否成功
*/
boolean initSlice();
/**
* 通知c++清除缓存
*/
void freeSliceCache();
/**
* 文件分片完成,释放资源
*/
void unInitSlice();
/**
* 获取分片数据
*
* @param filePath 完整文件路径
* @param objCounts 每个分片文件包含的实体数量
* @return 总的分片个数
*/
Integer fileSlice(WString filePath, int objCounts);
/**
* 获取序列号index的分片大小
*
* @param index
* @return 分片大小(单位byte)
*/
int getSliceBufferLength(int index);
/**
* 获取分片数据的字节数组
*
* @param index 分片序号
* @param pSliceBuffer 分片数据
* @return 是否成功
*/
boolean getSliceBuffer(int index, Pointer pSliceBuffer);
}

2.2、调用动态库的Java代码

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
public class SlicerService {
/**
* 每个分片中包含的实体数量
*/
private static final int objCountsPerPackage = 100;
/**
* 静态变量,确保不会被JVM垃圾回收
*/
private static SlicerLibrary library = null;
/**
* 初始化动态库标志位
*/
private static boolean initFlag = false;
public void saveSliceFile(String filePath) {
//初始化动态库
initSliceLibrary();
//c++对应的数据类型是w_chat
WString path = new WString(filePath);
//获取分片数量
Integer count = library.fileSlice(path, objCountsPerPackage);
//循环处理所有的分片
if (count != null && count > 0) {
for (int i = 0; i < count; i++) {
//获取每个分片文件的数据长度
int size = library.getSliceBufferLength(i);
//分配内存大小
Pointer buffer = new Memory(size);
try {
if (library.getSliceBuffer(i, buffer)) {
//获取数据
byte[] data = buffer.getByteArray(0, size);
//保存数据
saveData(data);
}
} finally {
//清除分配的内存
Native.free(Pointer.nativeValue(buffer));
//避免GC时,重复调用Native.free().而导致程序异常退出
Pointer.nativeValue(buffer, 0L);
//引用置空,便于垃圾回收
buffer = null;
}
}
}
}
/**
* 初始化动态库
*/
private void initSliceLibrary() {
if (!initFlag) {
library = SlicerLibrary.LIBRARY;
synchronized (this) {
if (!initFlag) {
initFlag = library.initSlice();
}
}
}
}
/**
* 保存实际数据
*
* @param data
*/
private void saveData(byte[] data) {
//省略保存逻辑
}
}

3、需要依赖的其他动态库的存放位置

将依赖的动态库,存放在linux服务器的任意文件夹下,然后将文件夹路径,配置进LD_LABRARY_PATH。

例如:/home/test,假设Java需要加载的入口so动态库是test1.so,c++文件工程结构如下:

则应该执行:

export LD_LABRARY_PATH=$LD_LABRARY_PATH:/home/test:/home/test/folder1:/home/test/folder2

注:$LD_LABRARY_PATH的作用是防止之前已经配置的路径被覆盖,在后面增加新的路径即可,多个文件夹路径通过冒号(:)分割。

4、export和LD_LABRARY_PATH说明

4.1、LD_LABRARY_PATH

LD_LABRARY_PATH是用于指定动态链接器(ld)查找ELF可执行文件运行时所依赖的动态库(so)的路径。即用于在程序运行期间查找动态链接库时,指定除了系统默认路径(/usr/lib)之外的路径。

LD_LABRARY_PATH,无法识别文件夹里面的子文件夹,子文件夹需要单独配置

4.2、export

Linux中,export命令用于新增、修改和删除Linux上的环境变量(对PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH),只针对当前用户当前窗口登录有效,新开窗口需要重新执行;

如果要使其永久生效,则需要在linux环境变量中配置,编辑vim ~/.bashrc ,增加export语句,然后source ~/.bashrc,使其立即生效。

参考:1、Linux中修改环境变量及生效方法(永久、临时)环境变量查看_linux 激活环境变量

2、Linux中PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH的区别_ld_library_path library_path 区别

posted @   浪迹天涯的派大星  阅读(721)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示