JNI 静态注册和动态注册

JNI 静态注册和动态注册
静态注册
  • 注册函数说明
    java 层声明 native 关键字修饰的函数,再使用 javah 编译得到 c/c++ 的头文件(.h),其包含 java_完整包名_类名_方法名 命名规则的桥接层函数。
    以下展示生成的头文件代码:
    #include <jni.h>
    
    #ifndef _JNI_DEMO_GREET_H // 避免头文件重复引用
    #define _JNI_DEMO_GREET_H
    
    #ifdef __cplusplus // c++ 支持函数重载,会在编译阶段把入参类型拼接在函数名后,这里注明使用 c 的编译方式.
    extern "C" {
    #endif
    
    JNIEXPORT jstring JNICALL Java_com_jnidemo_Greet_sayHello(JNIEnv *env, jclass clazz);
    JNIEXPORT void JNICALL Java_com_jnidemo_Greet_sayBye(JNIEnv *env, jclass clazz);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif // _JNI_DEMO_GREET_H
    
  • 静态注册的痛点
    • java 层包名/类名/函数名,任一处有改动,头文件及其实现函数的函数名称都会失效,需手动修改维护,查找繁琐且易出错。
    • 所有包含 native 函数的 java 类都需要编写 JNI头文件,且函数名过长。
    • 初次运行时需要建立 java与native 的jni函数映射关系, 影响运行效率。
动态注册
  • 注册流程
    Java-System.loadLibrary(libname) —>
    C-JNI_OnLoad —>
    Env->FindClass(classname) —>
    Env->RegisterNatives(JNINativeMethod[] - 函数映射表).

  • 注册函数说明
    以下展示 c/c++ 层桥接层代码:

      #include <jni.h>
    
      /**
       * JNINativeMethod 结构体描述
       * const char* name;      native函数名,之后java层函数名修改时同步修改该字段,包名类名修改时同步修改classname.
       * const char* signature; JNI 函数签名,需遵循桥接层签名规则。
       * void*       fnPtr;     c层实现函数的函数指针。
       */
      static JNINativeMethod gMethods1[] = {
              {"sayHello",         "()Ljava/lang/String;",     (void *) JniSayHello},
              {"sayBye",           "()V",                      (void *) JniSayBye}
      };
      
      static int registerNativesMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods, int numMethods) {
          jclass clazz = env->FindClass(className);
          if (clazz == NULL)
              return JNI_FALSE;
      
          if (env->RegisterNatives(clazz, gMethods, numMethods) < 0)
              return JNI_FALSE;
          return JNI_TRUE;
      }
      
      static int registerNatives(JNIEnv *env) {
          // 这里可以注册多个包含native函数的Java类
          int ret1 = registerNativesMethods(env, classname1, gMethods1, sizeof(gMethods1) / sizeof(gMethods1[0]));
          int ret2 = registerNativesMethods(env, classname2, gMethods2, sizeof(gMethods2) / sizeof(gMethods2[0]));
          return (ret1 && ret2) ? JNI_TRUE : JNI_FALSE;
      }
      
      JNIEXPORT jint JNICALL
      JNI_OnLoad(JavaVM *vm, void *reserved) {
          JNIEnv *env = NULL;
          if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK)
              return -1;
      
          assert(env != NULL);
          if (!registerNatives(env))
              return -1;
          return JNI_VERSION_1_6;
      }
    

参考文章:
JNI原理分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值