当前位置: 首页 > 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.gsyq.cn/news/55233.html

相关文章:

  • P2511 [HAOI2008] 木棍分割
  • MySQL高级运维核心技术:事务处理、安全管理与性能优化
  • 图文矩阵系统厂家综合测评推荐榜,抖音短视频矩阵/ai排名/短视频矩阵/ai排行榜/ai数字人矩阵/图文矩阵厂家推荐
  • nacos单机版安装
  • linux top命令配置重置还原
  • 第九章 顺序容器
  • 2025年岩棉板厂家权威推荐榜单:防排烟岩棉板/岩棉条/岩棉隔离带源头厂家精选
  • [完结13章]AI 编程必备 - 零基础 系统化学Python
  • 2025MathorCup大信息竞赛A题B题选题建议与分析,思路模型
  • SSH 客户端 MobarXterm 安装和使用笔记
  • 机器学习之决策树模型
  • 251119D. mod
  • 西门子MES已有质量模块,为何再斥资收购QMS?
  • 2025 年 11 月聚氨酯厂家推荐排行榜,聚氨酯组合料/黑白料/AB料/管道料/发泡剂,外墙/冷库聚氨酯保温材料公司精选
  • 2025安庆一对一家教机构推荐:五大辅导机构测评排行榜,综合实力全解析!
  • 邵阳一对一家教辅导机构推荐:2025年最新权威榜,全学段提分不踩坑
  • 2025马鞍山一对一家教机构推荐:五大辅导机构测评排行榜,综合实力全解析!
  • 马鞍山一对一辅导机构权威排行榜推荐:2025家教机构穿透式测评!
  • TalentsAI ——专家级大模型数据标注平台
  • 锁:lock、Monitor、SemaphoreSlim
  • 完整教程:ASP.NET MVC 前置基础:宿主环境 HttpRuntime 管道,从部署到流程拆透(附避坑指南)
  • 08_TCP服务器:一请求一线程 epoll
  • STM32学习(MCU控制)(USART) - 指南
  • NET 8 使用 rabbitMQ
  • 水波紋特效
  • 《说苑敬慎》中的故事
  • 实用指南:[从零开始面试算法] (04/100) LeetCode 136. 只出现一次的数字:哈希表与位运算的巅峰对决
  • [UOI2023] An Array and Partial Sums 题解(未完)
  • 关于某个视频的一点点想法
  • akm SharedWorker