来自:The Invocation API
举例说明如何使用Invocation API中的方法。下面使用C++代码创建一个Java VM,然后调用一个称为Main.test的static method。
Invocation API允许native application使用JNI interface pointer访问VM特性。
Eg:
#include /* where everything is defined */
...
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to native method interface */
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=/usr/lib/java";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
delete options;
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* We are done. */
jvm->DestroyJavaVM();
使用JNI_CreateJavaVM()方法加载和初始化一个Java VM,并且返回一个指向JNI interface pointer的指针。调用JNI_CreateJavaVM()方法的线程被认为是main thread
The JNI interface pointer(即JNIEnv)仅仅在当前线程有效。其他线程需要访问Java VM时,它必须调用 AttachCurrentThread() 方法attach它自己到VM,然后获取一个JNI interface pointer。一旦这个线程attach到VM,native thread工作就像一个普通的运行在native method中的Java thread一样(Once attached to the VM, a native thread works just like a ordinary Java thread running inside a native method)。这个native thread会一直attached VM,直到它调用 DetachCurrentThread() 方法detach它自己为止。
一个已经attach到VM的native thread在离开之前必须调用 DetachCurrentThread() detach它自己。如果有Java methods在调用栈中,thread不能detach它自己。
JNI_DestroyJavaVM()方法卸载Java VM。
只有current thread是唯一的non-daemon(非守护的) user thread时,VM才能真实地卸载掉。User thread包括Java thread和attached native thread。存在这个约束限制的原因是Java thread或者attached native thread 可能占用着系统资源,例如locks,windows等待。VM不能自动地释放这些资源。释放任意thread占用系统资源的操作由开发者去做。
(约束限制:当VM被卸载时,当前线程是唯一正在运行的线程。)
一旦native library被加载了,它是对所有class loaders是可见的。因此不同class loader中的两个类可能会与相同的native method关联上。这样导致两个问题:(暂不翻译)
解决方法是每个class loader管理它自己拥有的一系列native libraries。相同的JNI native library不能被多个class loader加载。否则会导致 UnsatisfiedLinkError。这种处理方法的好处:(暂不翻译)
jint JNI_OnLoad(JavaVM *vm, void *reserved);
当native library被加载后(例如通过 System.loadLibrary),VM会调用JNI_OnLoad。JNI_OnLoad必须返回被native library需要的JNI version。
如果VM不能识别JNI_OnLoad返回的version number,VM将会卸载library,就像这个library从来没有加载过一样。
JNI_Onload_L(JavaVM *vm, void *reserved);
Library L是一个静态链接。调用System.loadLibrary(“L”)或等效的API。它返回的JNI Version必须是JNI_VERSION_1_8或之上。
void JNI_OnUnload(JavaVM *vm, void *reserved);
当包含native library的class loader被GC后,VM会调用JNI_OnUnload。这个方法被用来执行清理操作。
JNI_OnUnload_L(JavaVM *vm, void *reserved);
当包含静态链接的native library L的class loader被GC后,VM会调用JNI_OnUnload_L。
JavaVM类型是一个指向Invocation API function table的指针。
The function table:
typedef const struct JNIInvokeInterface *JavaVM;
const struct JNIInvokeInterface ... = {
NULL,
NULL,
NULL,
DestroyJavaVM,
AttachCurrentThread,
DetachCurrentThread,
GetEnv,
AttachCurrentThreadAsDaemon
};
还有三个Invocation API functions(JNI_GetDefaultJavaVMInitArgs(),JNI_GetCreatedJavaVMs()和JNI_CreateJavaVM())不属于JavaVM function table。这三个方法可以被使用,不需要先有一个JavaVM structure。
方法介绍参考:Invocation API Functions