当前位置: 首页 > news >正文

windows和linux编写jni相关库,并使用动态调用来加载动态库

windows和linux编写jni相关库,并使用动态调用来加载动态库

1. 编写java代码

注意使用jni的代码,修改包名时,需要重新生成头文件并同步修改dll库相关代码,否则会导致无法链接错误


package org.example.testjni;import java.io.File;/*** 注意: 使用jni的代码,修改包名时,需要重新生成头文件并同步修改dll库相关代码,否则会导致无法链接错误*/
public class Decoder {private static String dllPath = null;private static long handle = 0L;private static Decoder decoder = null;public native String version();public String encode(String serial, int synctime) {return this.encode(handle, serial, synctime);}public String decode(String data) {return this.decode(handle, data);}private native long init(String dllPath);private native void kill(long handle);private native String encode(long handle, String serial, int synctime);private native String decode(long handle, String data);private Decoder() {}public void close() {if (handle != 0L) {decoder.kill(handle);handle = 0L;}decoder = null;}public static Decoder getDecoder() {if (decoder == null) {synchronized(Decoder.class) {decoder = new Decoder();handle = decoder.init(dllPath);}}return decoder;}/**** @param proxyDllPath 代理dll的目录地址,要求两个dll放置在同一目录*/public static void loadDll(String proxyDllPath) {String systemType = System.getProperties().getProperty("os.name");System.err.println("加载lib之前打点");String proxyFullPath = null;if (systemType.indexOf("Windows") != -1) {Decoder.dllPath = proxyDllPath + File.separator + "testdll.dll";proxyFullPath = proxyDllPath + File.separator + "testjni.dll";} else {Decoder.dllPath = proxyDllPath + File.separator + "testdll.so";proxyFullPath = proxyDllPath + File.separator + "testjni.so";}System.load(proxyFullPath);}public static void main(String[] args) {
//        String property = System.getProperty("java.library.path");
//        System.setProperty("java.library.path", property + File.pathSeparator + "E:\\test\\lib");
//        System.err.println(System.getProperty("java.library.path"));String systemType = System.getProperties().getProperty("os.name");System.err.println("加载lib之前打点");String proxyDllPath = null;if (systemType.indexOf("Windows") != -1) {proxyDllPath = "E:\\codes\\testjni\\temp";} else {proxyDllPath = "/root/code/cpp/testjni";}Decoder.loadDll(proxyDllPath);Decoder d = getDecoder();System.out.println("testdll version: " + d.version());String s = "encode_testdata";System.out.println(d.decode(s));s = "encode_testdata_2";System.out.println(d.decode(s));System.out.println(d.encode("testdata", 0));System.out.println(d.encode("testdata", 1));}}

2. windows下编译jni动态库

在vs向导页面创建一个dll库项目,并按如下设置,附加包含目录里面的目录路径是头文件路径
clip

此外要注意这个不使用预编译头,如果你使用了windows相关的api,但是没有正确的引用pch.h, 会报错,这个时候就需要设置不使用预编译头
clip_1

2.1. 目录结构

"jdk8_jni_heade"就是jdk根目录的include文件夹复制过来的,其实可以不用复制,直接在选项中指定目录位置就可以了

|--- include
|   |--- org_example_testjni_Decoder.h
|   |--- jdk8_jni_header(省略此文件夹内容,)
|--- testjni.h
|--- testjni.cpp

2.2. 本地库代码

org_example_testjni_Decoder.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_example_testjni_Decoder */#ifndef _Included_org_example_testjni_Decoder
#define _Included_org_example_testjni_Decoder
#ifdef __cplusplus
extern "C" {
#endif/** Class:     org_example_testjni_Decoder* Method:    version* Signature: ()Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_version(JNIEnv*, jobject);/** Class:     org_example_testjni_Decoder* Method:    init* Signature: (Ljava/lang/String;)J*/JNIEXPORT jlong JNICALL Java_org_example_testjni_Decoder_init(JNIEnv*, jobject, jstring);/** Class:     org_example_testjni_Decoder* Method:    kill* Signature: (J)V*/JNIEXPORT void JNICALL Java_org_example_testjni_Decoder_kill(JNIEnv*, jobject, jlong);/** Class:     org_example_testjni_Decoder* Method:    encode* Signature: (JLjava/lang/String;I)Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_encode(JNIEnv*, jobject, jlong, jstring, jint);/** Class:     org_example_testjni_Decoder* Method:    decode* Signature: (JLjava/lang/String;)Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_decode(JNIEnv*, jobject, jlong, jstring);#ifdef __cplusplus
}
#endif
#endif

testjni.h

#pragma once
#ifndef TESTJNI_H
#define TESTJNI_H#include "include/org_example_testjni_Decoder.h"#include <windows.h>#include <string>#endif //TESTJNI_H

testjni.cpp

#include "testjni.h"namespace {// 只能在本 .cpp 文件中访问static HMODULE hDll = NULL;using Version = jstring(*)(JNIEnv*, jobject); // 定义函数指针类型static Version version = NULL;using Init = jlong(*)(JNIEnv*, jobject); // 定义函数指针类型static Init init = NULL;using Kill = void(*)(JNIEnv*, jobject, jlong); // 定义函数指针类型static Kill kill = NULL;using Encode = jstring(*)(JNIEnv*, jobject, jlong, jstring, jint); // 定义函数指针类型static Encode encode = NULL;using Decode = jstring(*)(JNIEnv*, jobject, jlong, jstring); // 定义函数指针类型static Decode decode = NULL;/** 释放加载的dll*/void free_dll() {FreeLibrary(hDll);init = NULL;kill = NULL;version = NULL;encode = NULL;decode = NULL;hDll = NULL;}
}/** Class:     org_example_testjni_Decoder* Method:    version* Signature: ()Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_version
(JNIEnv* j_env, jobject j_obj) {if (version != NULL) {return version(j_env, j_obj);}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "version method is null!");return NULL;
}/** Class:     org_example_testjni_Decoder* Method:    init* Signature: ()J*/
JNIEXPORT jlong JNICALL Java_org_example_testjni_Decoder_init
(JNIEnv* j_env, jobject j_obj, jstring j_dll_full_path) {// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");if (hDll == NULL) {// 获取java字符串const char* dll_full_path = j_env->GetStringUTFChars(j_dll_full_path, nullptr);// 不使用绝对路径的直接使用testdll.dll,则会从系统库路径加载,比如项目根目录hDll = GetModuleHandleA(dll_full_path);if (NULL == hDll) {hDll = LoadLibraryA(dll_full_path);}// 释放字符串j_env->ReleaseStringUTFChars(j_dll_full_path, dll_full_path);if (NULL == hDll) {j_env->ThrowNew(cls_run_excep, "load testdll.dll fail!");// 错误处理return NULL;}}if (version == NULL) {version = (Version)GetProcAddress(hDll, "Java_org_example_testdll_Decoder_version");if (!version) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_version is not found!");return NULL;}}if (init == NULL) {init = (Init)GetProcAddress(hDll, "Java_org_example_testdll_Decoder_init");if (!init) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_init is not found!");return NULL;}}if (kill == NULL) {kill = (Kill)GetProcAddress(hDll, "Java_org_example_testdll_Decoder_kill");if (!kill) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_kill is not found!");return NULL;}}if (encode == NULL) {encode = (Encode)GetProcAddress(hDll, "Java_org_example_testdll_Decoder_encode");if (!kill) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_encode is not found!");return NULL;}}if (decode == NULL) {decode = (Decode)GetProcAddress(hDll, "Java_org_example_testdll_Decoder_decode");if (!decode) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_decode is not found!");return NULL;}}return init(j_env, j_obj);
}/** Class:     org_example_testjni_Decoder* Method:    kill* Signature: (J)V*/
JNIEXPORT void JNICALL Java_org_example_testjni_Decoder_kill
(JNIEnv* j_env, jobject j_obj, jlong j_handle) {if (kill != NULL) {kill(j_env, j_obj, j_handle);free_dll();}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "kill method is null!");
}/** Class:     org_example_testjni_Decoder* Method:    encode* Signature: (JLjava/lang/String;I)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_encode
(JNIEnv* j_env, jobject j_obj, jlong j_handle, jstring j_serial, jint j_synctime) {if (encode != NULL) {return encode(j_env, j_obj, j_handle, j_serial, j_synctime);}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "encode method is null!");return NULL;
}/** Class:     org_example_testjni_Decoder* Method:    decode* Signature: (JLjava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_decode
(JNIEnv* j_env, jobject j_obj, jlong j_handle, jstring j_data) {if (decode != NULL) {return decode(j_env, j_obj, j_handle, j_data);}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "decode method is null!");return NULL;
}

2.3 编译生成dll文件

直接点生成解决方案,就可以在项目根目录的相关目录找到

3. linux下编译jni动态库

3.2. 目录结构

"jdk8_jni_heade"就是jdk根目录的include文件夹复制过来的,其实可以不用复制,直接在选项中指定目录位置就可以了

|--- include
|   |--- org_example_testjni_Decoder.h
|   |--- jdk8_jni_header(省略此文件夹内容,)
|--- testjni.h
|--- testjni.cpp

3.2. 本地库代码

org_example_testjni_Decoder.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_example_testjni_Decoder */#ifndef _Included_org_example_testjni_Decoder
#define _Included_org_example_testjni_Decoder
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     org_example_testjni_Decoder* Method:    version* Signature: ()Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_version(JNIEnv *, jobject);/** Class:     org_example_testjni_Decoder* Method:    init* Signature: (Ljava/lang/String;)J*/
JNIEXPORT jlong JNICALL Java_org_example_testjni_Decoder_init(JNIEnv *, jobject, jstring);/** Class:     org_example_testjni_Decoder* Method:    kill* Signature: (J)V*/
JNIEXPORT void JNICALL Java_org_example_testjni_Decoder_kill(JNIEnv *, jobject, jlong);/** Class:     org_example_testjni_Decoder* Method:    encode* Signature: (JLjava/lang/String;I)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_encode(JNIEnv *, jobject, jlong, jstring, jint);/** Class:     org_example_testjni_Decoder* Method:    decode* Signature: (JLjava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_decode(JNIEnv *, jobject, jlong, jstring);#ifdef __cplusplus
}
#endif
#endif

testjni.h

#ifndef TESTJNI_H
#define TESTJNI_H#include "include/org_example_testjni_Decoder.h"#include <dlfcn.h>#include <string>#endif //TESTJNI_H

testjni.cpp

#include "testjni.h"// 匿名命名空间
namespace {// 只能在本 .cpp 文件中访问static void* hDll = NULL;using Version = jstring(*)(JNIEnv*, jobject); // 定义函数指针类型static Version version = NULL;using Init = jlong(*)(JNIEnv*, jobject); // 定义函数指针类型static Init init = NULL;using Kill = void(*)(JNIEnv*, jobject, jlong); // 定义函数指针类型static Kill kill = NULL;using Encode = jstring(*)(JNIEnv*, jobject, jlong, jstring, jint); // 定义函数指针类型static Encode encode = NULL;using Decode = jstring(*)(JNIEnv*, jobject, jlong, jstring); // 定义函数指针类型static Decode decode = NULL;/** 释放加载的dll*/void free_dll() {dlclose(hDll);init = NULL;kill = NULL;version = NULL;encode = NULL;decode = NULL;hDll = NULL;}
}/** Class:     org_example_testjni_Decoder* Method:    version* Signature: ()Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_version
(JNIEnv* j_env, jobject j_obj) {if (version != NULL) {return version(j_env, j_obj);}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "version method is null!");return NULL;
}/** Class:     org_example_testjni_Decoder* Method:    init* Signature: ()J*/
JNIEXPORT jlong JNICALL Java_org_example_testjni_Decoder_init
(JNIEnv* j_env, jobject j_obj, jstring j_dll_full_path) {// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");if (hDll == NULL) {// 获取java字符串const char* dll_full_path = j_env->GetStringUTFChars(j_dll_full_path, nullptr);// testdll.dllhDll = dlopen(dll_full_path,RTLD_LAZY);// 释放字符串j_env->ReleaseStringUTFChars(j_dll_full_path, dll_full_path);if (NULL == hDll) {fprintf(stderr,"%s ", dlerror());j_env->ThrowNew(cls_run_excep, "load testdll.so fail!");// 错误处理return 0;}}if (version == NULL) {version = (Version)dlsym(hDll, "Java_org_example_testdll_Decoder_version");if (!version) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_version is not found!");return 0;}}if (init == NULL) {init = (Init)dlsym(hDll, "Java_org_example_testdll_Decoder_init");if (!init) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_init is not found!");return 0;}}if (kill == NULL) {kill = (Kill)dlsym(hDll, "Java_org_example_testdll_Decoder_kill");if (!kill) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_kill is not found!");return 0;}}if (encode == NULL) {encode = (Encode)dlsym(hDll, "Java_org_example_testdll_Decoder_encode");if (!kill) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_encode is not found!");return 0;}}if (decode == NULL) {decode = (Decode)dlsym(hDll, "Java_org_example_testdll_Decoder_decode");if (!decode) {free_dll();j_env->ThrowNew(cls_run_excep, "Java_org_example_testdll_Decoder_decode is not found!");return 0;}}return init(j_env, j_obj);
}/** Class:     org_example_testjni_Decoder* Method:    kill* Signature: (J)V*/
JNIEXPORT void JNICALL Java_org_example_testjni_Decoder_kill
(JNIEnv* j_env, jobject j_obj, jlong j_handle) {if (kill != NULL) {kill(j_env, j_obj, j_handle);free_dll();}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "kill method is null!");
}/** Class:     org_example_testjni_Decoder* Method:    encode* Signature: (JLjava/lang/String;I)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_encode
(JNIEnv* j_env, jobject j_obj, jlong j_handle, jstring j_serial, jint j_synctime) {if (encode != NULL) {return encode(j_env, j_obj, j_handle, j_serial, j_synctime);}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "encode method is null!");return NULL;
}/** Class:     org_example_testjni_Decoder* Method:    decode* Signature: (JLjava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_org_example_testjni_Decoder_decode
(JNIEnv* j_env, jobject j_obj, jlong j_handle, jstring j_data) {if (decode != NULL) {return decode(j_env, j_obj, j_handle, j_data);}// 获取异常类jclass cls_run_excep = j_env->FindClass("java/lang/RuntimeException");j_env->ThrowNew(cls_run_excep, "decode method is null!");return NULL;
}

3.3. 使用g++编译

g++ testjni.cpp -std=c++14 -I ./include -I ./include/jdk8_jni_header/ -I ./include/jdk8_jni_header/linux/ -fPIC -shared -o testjni.so

4.总结linux和windows下的动态库的动态加载差异

功能 windows linux 附加说明
动态库后缀名 以.dll作为后缀,是PE文件格式 以lib开头,以.so作为后缀 存在差异
定义函数指针 using Kill = void()(JNIEnv, jobject, jlong); using Kill = void()(JNIEnv, jobject, jlong); 完全一样
使用函数指针 kill(j_env, j_obj, j_handle) kill(j_env, j_obj, j_handle) 完全一样
加载动态库api HMODULE hDll= GetModuleHandleA(dll_full_path);/HMODULE hDll= LoadLibraryA(dll_full_path); void* hDll = dlopen(dll_full_path,RTLD_LAZY); 存在差异
加载动态库函数api decode = (Decode)GetProcAddress(hDll, "Java_org_example_testdll_Decoder_decode"); decode = (Decode)dlsym(hDll, "Java_org_example_testdll_Decoder_decode"); 存在差异
释放动态库函数api FreeLibrary(hDll); dlclose(hDll); 存在差异
http://www.jsqmd.com/news/45597/

相关文章:

  • 2025年移动方舱订做厂家权威推荐榜单:集装箱房/军用方舱/宿营方舱源头厂家精选
  • 数据结构-线段树
  • 第十一章 泛型算法
  • P2511 [HAOI2008] 木棍分割
  • 国标GB28181算法算力平台EasyGBS:构建“智慧消防”可视化管理与预警新模式
  • MySQL高级运维核心技术:事务处理、安全管理与性能优化
  • 实用指南:链表-双向链表【node3】
  • Vue中,list集合中包含实体(对象)的列表,存在某个特定的值在实体类属性是否存在常见的方法:
  • 2025年复合涤纶布优质厂家权威推荐榜单:涂层涤纶布/阻燃涤纶布/防水涤纶布源头厂家精选
  • List相关知识点
  • 图文矩阵系统厂家综合测评推荐榜,抖音短视频矩阵/ai排名/短视频矩阵/ai排行榜/ai数字人矩阵/图文矩阵厂家推荐
  • ubuntu22.04 安装OpenSSH-server 支持vscode 远程
  • 2025年工业溶氧仪实力厂家权威推荐榜单:溶氧分析仪/溶解氧分析仪/在线溶解氧分析仪源头厂家精选
  • nacos单机版安装
  • linux top命令配置重置还原
  • Linux中: 通过 iostat 怎么判断硬盘是否存在I/O瓶颈
  • 2025 年便携式 VOC 气体检测仪、气体检测仪厂家十大品牌推荐:精准监测筑牢安全防线,智能传感赋能行业发展
  • RustFS vs MinIO:谁才是国产高性能对象存储之光?
  • SOLID原则在React中的应用实践
  • 绘图工具
  • 深入解析:BERT,GPT,ELMO模型对比
  • 2025 年 11 月离心机厂家推荐排行榜,台式低速大容量离心机,血液离心机,台式低速离心机,台式指针式离心机,台式离心机,小高速离心机,低速微电脑控制离心机,六乘五十毫升离心机,高速离心机公司推荐
  • 2025MathorCup大信息竞赛A题B题选题建议与分析,思路模型
  • Redis更新缓存之双重检查 - 邓维
  • SSH 客户端 MobarXterm 安装和使用笔记
  • 已有ERP和MES,为什么还需要质量管理系统(QMS)?
  • 2025年质量气体流量计直销厂家权威推荐榜单:超微量气体流量计/甲烷气体流量计/小口径气体流量计源头厂家精选
  • SBD3D60V1H-ASEMI可直接替代安世PMEG6010CEJ
  • 机器学习之决策树模型
  • 重庆一对一辅导机构精选推荐,2025合规家教机构口碑排名已公布,附师资实力测评