1. 程式人生 > >JNI-通過C++呼叫JAVA

JNI-通過C++呼叫JAVA

1、背景

    在Report_Center_Task_Proc上報訊息執行緒中,我們在訊息佇列裡面獲取到資料後,把資料簡單解析後通過java介面g_jniEnv->CallVoidMethod上報資料,那什麼在c++程式碼中怎麼呼叫java函式方法的呢?

    首先,JNI介面初始化會傳入JNIEnv *env, jobject instance。

    JNIEXPORT void JNICALL Java_com_starcor_data_needle_crawler_crawl_NeedleJNI_init(JNIEnv

*env, jobject instance)

2、JNIEnv物件

    JNIEnv型別代表Java環境。通過這個JNIEnv*指標,就可以對Java端的程式碼進行操作。如,建立Java類的物件,呼叫Java物件的方法,獲取Java物件的屬性等。

    JNIEnv的指標會被JNI傳送到本地方法的實現函式中來對Java端的程式碼進行操作

    JNIEnv類中的函式:

     NewObject/NewString/New<TYPE>Array  :new新物件

     Get/Set<TYPE>Field:獲取屬性

     Get/SetStatic<TYPE>Field :獲取靜態屬性

     Call<TYPE>Method/CallStatic<TYPE>Method:呼叫方法

    我們的介面呼叫

  init rp->updateContext(JNIEnv *_jniEnv, jobject _jobject); 

     _jniEnv->GetJavaVM(&gJVM);

     g_jobject = _jniEnv->NewGlobalRef(_jobject);      

  使用時通過gJVM獲取到g_jniEnv:

     gJVM->GetEnv((void **)&g_jniEnv, JNI_VERSION_1_6);

3、獲取jclass

    為了能夠在C/C++使用Java類,jni.h標頭檔案中專門定義了jclass型別來表示Java中的Class類

    jclass的取得:

    JNIEnv類中有如下幾個簡單的函式可以取得jclass

    jclass FindClass(const char* clsName)  根據類名來查詢一個類,完整類名。

    jclass GetObjectClass(jobject obj)   根據一個物件,獲取該物件的類

    jclass GetSuperClass(jclass obj)     獲取一個類的父類

    FindClass 會在classpath系統環境變數下尋找類,需要傳入完整的類名,注意包與包之間是用"/"而不是"."來分割

如:jclass cls_string= env->FindClass("java/lang/String");

獲取jclass又什麼用,比如你要呼叫類的靜態方法,靜態屬性就需要通過這個方法來獲取一個類。

    我們的介面呼叫:

jclass eventClass = g_jniEnv->GetObjectClass(g_jobject);

4、原生代碼訪問Java類中的屬性與方法

    有了類和物件之後,如何才能訪問java中的物件的屬性和方法呢,這就需要用到以下這些方法了。

JNI在jni.h標頭檔案中定義了jfieldID,jmethodID類表示Java端的屬性和方法

如何獲取屬性: 在訪問或設定Java屬性的時候,首先就要現在原生代碼中取得代表Java屬性的jfieldID,然後才能在原生代碼中進行Java屬性操作。

    如何呼叫java的方法:呼叫Java端的方法時,需要取得代表方法的jmethodID才能進行Java方法呼叫

JNIEnv獲取相應的fieldID和jmethodID的方法:

    GetFieldID/GetMethodID

    GetStaticFieldID/GetStaticMethodID

    GetMethodID也可以取得建構函式的jmethodID。建立Java物件時呼叫指定的建構函式。

    如:env->GetMethodID(data_Clazz,"method_name","()V")

    (*jniEnv)->GetMethodID(jniEnv, Clazz,"<init>", "()V");

    這個比較特殊,這個是預設建構函式的方法,一般用這個來初始化物件,但是再實際過程中,為了快速生成一個例項,一般通過工廠方法類建立jobject

    jni.h 對GetMethodID的定義:

    jmethodID (JNICALL *GetMethodID)

      (JNIEnv *env, jclass clazz, const char *name, const char *sig);

我們的介面呼叫:

jmethodID event_cb = g_jniEnv->GetMethodID(eventClass, "reportHttpPackageData", DEF_METH);

        DEF_METH的定義:

#define DEF_METH "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;[BLjava/lang/String;I)V"

5、資料轉換

jstring flowkey = char2Jsting(g_jniEnv, MsgData->flowKey);

6、呼叫java方法event_cb上報資料

g_jniEnv->CallVoidMethod(g_jobject, \

            event_cb, \

            flowkey, \

            flowtime, \

            filterid, \

            requsthead, \

            requst, \

            responsehead, \

            response, \

            statistics, \

            MsgData->State);

就是呼叫java裡面NeedleJNI 的reportHttpPackageData方法。