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
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方法。