基于JDK21+Windows 环境的动态注册JNI 示例

122 阅读2分钟

1. Java 代码 (DynamicJNIDemo.java)

public class DynamicRegisterDemo {
    static {
        System.loadLibrary("dynamicregister"); // 加载动态库 dynamicregister.dll
    }

    // 声明 native 方法
    public native void sayHello();

    public static void main(String[] args) {
        new DynamicRegisterDemo().sayHello();
    }
}

2. C++ 实现 (DynamicJNIDemo.cpp)

#include <jni.h>
#include <iostream>

// 本地方法实现
void nativeSayHello(JNIEnv* env, jobject obj) {
    std::cout << "Hello from dynamically registered JNI method!" << std::endl;
}

// 定义方法表(关键:方法签名必须与 Java 方法严格匹配)
static JNINativeMethod methods[] = {
    {"sayHello", "()V", (void*)&nativeSayHello} // 方法名、签名、函数指针
};

// JNI_OnLoad 入口函数(动态注册的核心)
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = nullptr;
    jint result = vm->GetEnv((void**)&env, JNI_VERSION_21);
    if (result != JNI_OK) {
        return JNI_ERR;
    }

    // 获取 Java 类对象
    jclass clazz = env->FindClass("DynamicRegisterDemo");
    if (clazz == nullptr) {
        return JNI_ERR;
    }

    // 注册本地方法
    if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]) < 0)) {
        return JNI_ERR;
    }

    return JNI_VERSION_21
;
}

2. 编译动态库(Windows)

使用 MinGW

 g++ -I $JAVA_HOME/include -I $JAVA_HOME/include/win32 -shared -o dynamicregister.dll DynamicRegisterDemo.cpp

3. 运行程序

java -Djava.library.path=. DynamicRegisterDemo

动态注册的核心优势

特性说明
函数名自由无需遵循 Java_ClassName_MethodName 的严格命名规则。
延迟绑定可在运行时动态注册或替换方法实现。
减少头文件依赖无需通过 javac -h 生成头文件,直接通过方法表绑定。
代码更简洁集中管理所有 JNI 方法,适合大型项目。

常见问题解决

1. UnsatisfiedLinkError 错误

  • 原因:动态库未找到或注册失败。

  • 解决

    • 确保动态库名称与 System.loadLibrary("dynamicregister") 中的名称一致(Windows 要求库名为 dynamicregister.dll)。
    • 检查 java.library.path 是否包含动态库所在目录。

2. RegisterNatives 注册失败

  • 原因:方法签名错误或类名不匹配。

  • 解决

    • 使用 javap -s 确保方法签名严格一致。
    • 检查类名全路径(如果类在包中,需使用 com/example/DynamicRegisterDemo 格式)。

3. JNI 版本冲突

  • 原因:未在 JNI_OnLoad 中返回正确的 JNI 版本。
  • 解决:确保返回 JNI_VERSION_1_8 或更高版本(JDK21 兼容 1.8)。