JNI 静态注册和动态注册

JNI 静态注册和动态注册

静态注册
  • 注册函数说明
    java 层声明 native 关键字修饰的函数,再使用 javah 编译得到 c/c++ 的头文件(.h),其包含 java_完整包名_类名_方法名 命名规则的桥接层函数。
    以下展示生成的头文件代码:
    #include 
    
    #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 
    
      /**
       * 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原理分析

你可能感兴趣的:(JNI,JNI,静态注册,动态注册)