JNI:通过函数名对应表的方式来加载对应的native方法

我们在HelloWorld.java中定义的private native void print()调用时,

怎么就会调用到我们底层的Java_com_worthcloud_HelloWorld_print(JNIEnv *env,jobject obj)函数呢?这里先大概了解一下Java中我们本地库的加载

方式:System.loadlibrary(libraryname)。该函数会在适当的路劲加载动态库文件,然后通过类似于dlsym(handle,"JNI_OnLoad")方法来执行JNI_OnLoad

函数。这样我们就可以在JNI_OnLoad()这样一个函数中做一些事情以影响后续的程序代码执行。我们这章介绍的通过函数名对应表的方式来加载native方法

就是在这里面做了些文章的。


       在Java运行时,其内部会维持一个native函数库表,这里我们暂且称为native_sym_tbl,该开始这个表示空的。当在执行到某一个native方法时,例如执行到

new HelloWorld().print()这个natvie方法时,就从native_sym_tbl这个表中查找该print函数对应的底层实现函数原型,而此时该表为空,肯定查找不到,这时就会

采用默认的Java_完整类名_函数名()的方式在动态加载库中查找该函数,针对前面的print()这个函数,就会执行如下查找Java_com_worthcloud_HelloWorld_print()

方法,然后执行该函数,没有找到则直接报错。那么,如果我们通过适当的方法,预先填好native_sym_tbl这个表,则在后续的执行中则可以直接对应到底层的

实现函数,并且这样还未我们带来了一个副产品:可以将Java中声明的native方法名称映射为我们自己的名称,而不需要按照其默认的方式。


看如下实现:

HelloWorld.java

[java]  view plain  copy
  1. package com.worthcloud;  
  2.   
  3. class HelloWorldUtils  
  4. {  
  5.     public native void print();  
  6. }  
  7.    
  8.   
  9. class Prompt  
  10. {   
  11.     public native String getLine(String prompt);  
  12. }  
  13.   
  14.   
  15. public class HelloWorld {  
  16.   
  17.       
  18.     private native void print();  
  19.     public native String getLine(String prompt);  
  20.       
  21.     public static void main(String[] args) {  
  22.         // TODO Auto-generated method stub  
  23.         new HelloWorldUtils().print();  
  24.       
  25.         new HelloWorld().print();  
  26.           
  27.         while(true)  
  28.             System.out.println("Output:"+new Prompt().getLine("Input:"));  
  29.     }  
  30.   
  31.     static  
  32.     {  
  33.         System.loadLibrary("helloworld");  
  34.     }  
  35.       
  36.   
  37. }  



JNI_HelloWorld.c:
[cpp]  view plain  copy
  1. "code" class="cpp">#include   
  2. #include   
  3. #include "jni_helloworld.h"  
  4.   
  5.   
  6. #define HELLOWORLDUTILS_CP      "com/worthcloud/HelloWorldUtils"  
  7. #define HELLOWORLD_CP           "com/worthcloud/HelloWorld"  
  8. #define PROMPT_CP               "com/worthcloud/Prompt"  
  9.   
  10.   
  11. /** 
  12. * Class: com_worthclould_HelloWorldUtils_print 
  13. * Method: print 
  14. * Signature: ()V 
  15. */  
  16. JNIEXPORT void JNICALL JNI_HelloWorldUtils_print(JNIEnv *env, jobject obj)  
  17. {  
  18.     printf("Hello World - (utils)\n");  
  19.     fflush(stdout);  
  20. }  
  21.   
  22. /** 
  23. * Class: com_worthclould_HelloWorld_print 
  24. * Method: print 
  25. * Signature: ()V 
  26. */  
  27. JNIEXPORT void JNICALL JNI_HelloWorld_print(JNIEnv *env, jobject obj)  
  28. {  
  29.     printf("Hello World\n");  
  30.     fflush(stdout);  
  31. }  
  32.   
  33. /** 
  34. * Class: com_worthcloud_Prompt 
  35. * Method: getLine 
  36. * Signature: (Ljava/lang/String;)Ljava/lang/String; 
  37. */  
  38. JNIEXPORT jstring JNICALL JNI_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)  
  39. {  
  40.     char buf[128];  
  41.     const char *str;  
  42.     str = (*env)->GetStringUTFChars(env, prompt, NULL);  
  43.     if (str == NULL)  
  44.         return NULL;    /*OutOfMemoryError already thrown*/  
  45.   
  46.     printf("%s", str);  
  47.     fflush(stdout);  
  48.     (*env)->ReleaseStringUTFChars(env, prompt, str);  
  49.   
  50.     /** 
  51.     * We assume here that the user does not type more than 127 characters 
  52.     */  
  53.     scanf_s("%s", buf);  
  54.        
  55.     return (*env)->NewStringUTF(env, buf);  
  56. }  
  57.   
  58. //接口输出函数表  
  59. static JNINativeMethod gHelloWorldUtilsMethods[] = {  
  60.     {  
  61.         "print",  
  62.         "()V",  
  63.         (void *)JNI_HelloWorldUtils_print  
  64.     }  
  65. };  
  66.   
  67. static JNINativeMethod gHelloWorldMethods[] = {  
  68.     {  
  69.         "print",  
  70.         "()V",  
  71.         (void *)JNI_HelloWorld_print  
  72.     }  
  73. };  
  74.   
  75. static JNINativeMethod gPromptMethods[] = {  
  76.     {  
  77.         "getLine",  
  78.         "(Ljava/lang/String;)Ljava/lang/String;",  
  79.         (void *)JNI_Prompt_getLine  
  80.     }  
  81. };  
  82.   
  83. /** 
  84.  * description: 针对类名,注册多个native 接口函数 
  85.  *  
  86.  * env: 代表Java环境,通过这个环境可以调用JNIEnv中的相关方法 
  87.  * className: Java类名称 
  88.  * pMethods: 接口函数表 
  89.  * nMethods: 接口函数中函数的个数 
  90. */  
  91. static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *pMethods, int nMethods)  
  92. {  
  93.     jclass clazz;  
  94.   
  95.     if ((clazz = (*env)->FindClass(env, className)) == NULL)  
  96.         return -1;  
  97.       
  98.     if ((*env)->RegisterNatives(env, clazz, pMethods, nMethods) != JNI_OK)  
  99.         return -2;  
  100.   
  101.     return 0x0;  
  102. }  
  103.   
  104.   
  105. /** 
  106.  * 方法名称规定: jni 入口函数 
  107.  *  
  108.  * 参数介绍: 
  109.  * vm: 虚拟机指针 
  110. */  
  111.   
  112. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)  
  113. {  
  114.     JNIEnv *env = NULL;  
  115.     jint result = 0;  
  116.   
  117.     if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK || env == NULL)  
  118.     {  
  119.         result = -1;  
  120.         goto end;  
  121.     }  
  122.       
  123.     if (registerNativeMethods(env, HELLOWORLDUTILS_CP, gHelloWorldUtilsMethods,  
  124.         sizeof(gHelloWorldUtilsMethods) / sizeof(JNINativeMethod)) < 0)  
  125.     {  
  126.         result = -2;  
  127.         goto end;  
  128.     }  
  129.   
  130.     if (registerNativeMethods(env, HELLOWORLD_CP, gHelloWorldMethods,  
  131.         sizeof(gHelloWorldMethods) / sizeof(JNINativeMethod)) < 0)  
  132.     {  
  133.         result = -3;  
  134.         goto end;  
  135.     }  
  136.   
  137.     if (registerNativeMethods(env, PROMPT_CP, gPromptMethods,  
  138.         sizeof(gPromptMethods) / sizeof(JNINativeMethod)) < 0)  
  139.     {  
  140.         result = -4;  
  141.         goto end;  
  142.     }  
  143.   
  144.   
  145.     result = JNI_VERSION_1_4;  
  146.   
  147. end:  
  148.     if (result < 0)  
  149.     {  
  150.         printf("JNI_OnLoad failure(ret:%d)\n", result);  
  151.     }  
  152.     return result;  
  153. }  

  154.   

  155.   
  156.   
2
 
0

你可能感兴趣的:(JNI:通过函数名对应表的方式来加载对应的native方法)