The Invocation API allows software vendors to loadthe Java VM into an arbitrary native application. Vendors candeliver Java-enabled applications without having to link with theJava VM source code.
This chapter begins with an overview of theInvocation API. This is followed by reference pages for allInvocation API functions.
The following code example illustrates how to usefunctions in the Invocation API. In this example, the C++ codecreates a Java VM and invokes a static method, called Main.test
. For clarity, we omit error checking.
#include <jni.h> /* 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, &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();
This example uses three functions in the API. TheInvocation API allows a native application to use the JNI interfacepointer to access VM features. The design is similar toNetscape’s JRI Embedding Interface.
The JNI_CreateJavaVM()
function loads and initializes a Java VM and returns a pointer tothe JNI interface pointer. The thread that called JNI_CreateJavaVM()
is considered to be themain thread.
The JNI interface pointer (JNIEnv
) is valid only in the current thread. Shouldanother thread need to access the Java VM, it must first callAttachCurrentThread()
to attach itselfto the VM and obtain a JNI interface pointer. Once attached to theVM, a native thread works just like an ordinary Java thread runninginside a native method. The native thread remains attached to theVM until it calls DetachCurrentThread()
to detach itself.
The attached thread should have enough stack spaceto perform a reasonable amount of work. The allocation of stackspace per thread is operating system-specific. For example, usingpthreads, the stack size can be specified in the pthread_attr_t
argument to pthread_create
.
A native thread attached tothe VM must call DetachCurrentThread()
to detachitself before exiting. A thread cannot detach itself if there areJava methods on the call stack.
The JNI_DestroyJavaVM()
function unloads a Java VM. Asof JDK/JRE 1.1, only the main thread could unload the VM, bycalling DestroyJavaVM
. As of JDK/JRE 1.2, therestriction was removed, and any thread may callDestroyJavaVM
to unload the VM.
The VM waits until the current thread is the only non-daemon user thread before it actually unloads.User threads include both Java threads and attached native threads.This restriction exists because a Java thread or attached nativethread may be holding system resources, such as locks, windows, andso on. The VM
cannot automatically freethese resources. By restricting the current thread to be the only runningthread when the VM is unloaded, the burden of releasing systemresources held by arbitrary threads is on the programmer.
As of JDK/JRE 1.2, each class loader manages its own set ofnative libraries. The same JNI native library cannot beloaded into more than one class loader. Doing so causesUnsatisfiedLinkError
to be thrown. For example,System.loadLibrary
throws anUnsatisfiedLinkError
when used to load a nativelibrary into two class loaders. The benefits of the new approachare:
To facilitate version control and resource management, JNIlibraries as of JDK/JRE 1.2 optionally export the following twofunctions:
jint JNI_OnLoad(JavaVM *vm, void *reserved);
The VM callsJNI_OnLoad
when the nativelibrary is loaded (for example, throughSystem.loadLibrary
).JNI_OnLoad
mustreturn the JNI version needed by the native library.In order to use any of the new JNI functions, a native librarymust export a
JNI_OnLoad
function that returnsJNI_VERSION_1_2
. If the native library does not exportaJNI_OnLoad
function, the VM assumes that the libraryonly requires JNI versionJNI_VERSION_1_1
. If the VMdoes not recognize the version number returned byJNI_OnLoad
, the native library cannot be loaded.
Exported from native libraries that containnative method implementation.
JDK/JRE 1.4
In order to use the JNI functions introduced in J2SE release1.2, in addition to those that were available in JDK/JRE 1.1, anative library must export a
JNI_OnLoad
function thatreturnsJNI_VERSION_1_2
.In order to use the JNI functions introduced in J2SE release1.4, in addition to those that were available in release 1.2, anative library must export a
JNI_OnLoad
function thatreturnsJNI_VERSION_1_4
.If the native library does not export a
JNI_OnLoad
function, the VM assumes that the library only requires JNI versionJNI_VERSION_1_1
. If the VM does not recognize theversion number returned byJNI_OnLoad
, the nativelibrary cannot be loaded.
void JNI_OnUnload(JavaVM *vm, void *reserved);
The VM calls JNI_OnUnload
when the classloader containing the native library is garbage collected. Thisfunction can be used to perform cleanup operations. Because thisfunction is called in an unknown context (such as from afinalizer), the programmer should be conservative on using Java VMservices, and refrain from arbitrary Java call-backs.
Note that JNI_OnLoad
and JNI_OnUnload
are two functions optionally supplied by JNI libraries, notexported from the VM.
The JavaVM
type is apointer to the Invocation API function table. The following codeexample shows this function table.
typedef const struct JNIInvokeInterface *JavaVM;const struct JNIInvokeInterface ... = { NULL, NULL, NULL, DestroyJavaVM, AttachCurrentThread, DetachCurrentThread, GetEnv, AttachCurrentThreadAsDaemon};
Note that three Invocation API functions,JNI_GetDefaultJavaVMInitArgs()
,JNI_GetCreatedJavaVMs()
, and JNI_CreateJavaVM()
, are not part of the JavaVMfunction table. These functions can be used without a preexistingJavaVM
structure.
jintJNI_GetDefaultJavaVMInitArgs(void *vm_args);
Returns a default configuration for the Java VM.Before calling this function, native code must set thevm_args->version field to the JNI version it expects the VM tosupport. After this function returns, vm_args->version will beset to the actual JNI version the VM supports.
Exported from the native library thatimplements the Java virtual machine.
vm_args
: a pointer to aJavaVMInitArgs
structure in to which thedefault arguments are filled.
Returns JNI_OK
if therequested version is supported; returns a JNI error code (anegative number) if the requested version is not supported.
jintJNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize*nVMs);
Returns all Java VMs that have been created.Pointers to VMs are written in the buffer vmBuf in the order theyare created. At most bufLen number of entries will be written. Thetotal number of created VMs is returned in *nVMs.
As of JDK/JRE 1.2, creation of multiple VMs in asingle process is not supported.
Exported from the native library thatimplements the Java virtual machine.
vmBuf
: pointer to thebuffer where the VM structures will be placed.
bufLen
: the length ofthe buffer.
nVMs
: a pointer to aninteger.
Returns JNI_OK
onsuccess; returns a suitable JNI error code (a negative number) onfailure.
jint JNI_CreateJavaVM(JavaVM**p_vm, JNIEnv **p_env, void *vm_args);
Loads and initializes a Java VM. The currentthread becomes the main thread. Sets the env
argument to the JNI interface pointer of themain thread.
The second argument to JNI_CreateJavaVM
is always a pointer to JNIEnv *
, while the third argument is a pointer to aJavaVMInitArgs
structure which usesoption strings to encode arbitrary VM start up options:
typedef struct JavaVMInitArgs { jint version; jint nOptions; JavaVMOption *options; jboolean ignoreUnrecognized;} JavaVMInitArgs;
The version
field must be set to at leastJNI_VERSION_1_2
. The options
field is anarray of the following type:
typedef struct JavaVMOption { char *optionString; /* the option as a string in the default platform encoding */ void *extraInfo;} JavaVMOption;
The size of the array is denoted by the nOptions field inJavaVMInitArgs
. If ignoreUnrecognized
isJNI_TRUE
, JNI_CreateJavaVM
ignore allunrecognized option strings that begin with "-X
" or"_
". If ignoreUnrecognized
isJNI_FALSE
, JNI_CreateJavaVM
returnsJNI_ERR
as soon as it encounters any unrecognizedoption strings. All Java VMs must recognize the following set ofstandard options:
optionString meaning -D<name>=<value>
Set a system property -verbose[:class|gc|jni]
Enable verbose output. The options can be followed by acomma-separated list of names indicating what kind of messages willbe printed by the VM. For example, " -verbose:gc,class
"instructs the VM to print GC and class loading related messages.Standard names include:gc
,class
, andjni
. All nonstandard (VM-specific) names must beginwith "X
".vfprintf
extraInfo
is a pointer to thevfprintf
hook.exit
extraInfo
is a pointer to theexit
hook.abort
extraInfo
is a pointer to theabort
hook.
In addition, each VM implementation may support its own set ofnon-standard option strings. Non-standard option names must beginwith "-X
" or an underscore ("_
"). Forexample, the JDK/JRE supports -Xms
and-Xmx
options to allow programmers specify the initialand maximum heap size. Options that begin with "-X
"are accessible from the "java
" command line.
Here is the example code that creates a Java VM in theJDK/JRE:
JavaVMInitArgs vm_args;JavaVMOption options[4];options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */options[2].optionString = "-Djava.library.path=c:\mylibs"; /* set native library path */options[3].optionString = "-verbose:jni"; /* print JNI-related messages */vm_args.version = JNI_VERSION_1_2;vm_args.options = options;vm_args.nOptions = 4;vm_args.ignoreUnrecognized = TRUE;/* Note that in the JDK/JRE, there is no longer any need to call * JNI_GetDefaultJavaVMInitArgs. */res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);if (res < 0) ...
Exported from the native library thatimplements the Java virtual machine.
p_vm
: pointer to thelocation where the resulting VM structure will be placed.
p_env
: pointer to thelocation where the JNI interface pointer for the main thread willbe placed.
vm_args
: Java VMinitialization arguments.
Returns JNI_OK
onsuccess; returns a suitable JNI error code (a negative number) onfailure.
jint DestroyJavaVM(JavaVM*vm);
Unloads a Java VM and reclaims its resources.
The support for DestroyJavaVM
was notcomplete in JDK/JRE 1.1. As of JDK/JRE 1.1 Only the main thread maycall DestroyJavaVM
. Since JDK/JRE 1.2, any thread, whetherattached or not, can call this function. If the current thread isattached, the VM waits until the current thread is the onlynon-daemon user-level Java thread. Ifthe current thread is not attached, the VM attaches the currentthread and then waits until the current thread is the onlynon-daemon user-level thread. TheJDK/JRE still does not support VM unloading, however.
Index 3 in the JavaVM interface functiontable.
vm
: the Java VM thatwill be destroyed.
Returns JNI_OK
onsuccess; returns a suitable JNI error code (a negative number) onfailure.
As of JDK/JRE 1.1.2 unloading of the VM is notsupported.
jintAttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void*thr_args);
Attaches the current thread to a Java VM. Returnsa JNI interface pointer in the JNIEnv
argument.
Trying to attach a thread that is already attachedis a no-op.
A native thread cannot be attached simultaneouslyto two Java VMs.
When a thread is attached to the VM, the contextclass loader is the bootstrap loader.
Index 4 in the JavaVM interface functiontable.
vm
: the VM to which thecurrent thread will be attached.
p_env
: pointer to thelocation where the JNI interface pointer of the current thread willbe placed.
thr_args
: can be NULLor a pointer to a JavaVMAttachArgs
structure to specify additional information:
As of JDK/JRE 1.1, the second argument toAttachCurrentThread
is always a pointer toJNIEnv
. The third argument toAttachCurrentThread
was reserved, and should be set toNULL
.
As of JDK/JRE 1.2, you pass NULL
as the thirdargument for 1.1 behavior, or pass a pointer to the followingstructure to specify additional information:
typedef struct JavaVMAttachArgs { jint version; /* must be at least JNI_VERSION_1_2 */ char *name; /* the name of the thread as a modified UTF-8 string, or NULL */ jobject group; /* global ref of a ThreadGroup object, or NULL */} JavaVMAttachArgs
Returns JNI_OK
onsuccess; returns a suitable JNI error code (a negative number) onfailure.
jint AttachCurrentThreadAsDaemon(JavaVM* vm, void** penv,void* args);
Same semantics as AttachCurrentThread, but thenewly-created java.lang.Thread instance is adaemon.
If the thread has already been attached via eitherAttachCurrentThread orAttachCurrentThreadAsDaemon, this routine simply sets thevalue pointed to by penv to the JNIEnv of thecurrent thread. In this case neither AttachCurrentThreadnor this routine have any effect on the daemon status ofthe thread.
Index 7 in the JavaVM interface functiontable.
vm: the virtual machine instance to which the currentthread will be attached.
penv: a pointer to the location in which theJNIEnv interface pointer for the current thread will beplaced.
args: a pointer to a JavaVMAttachArgsstructure.
Returns JNI_OK
onsuccess; returns a suitable JNI error code (a negative number) onfailure.
None.
JDK/JRE 1.4
jintDetachCurrentThread(JavaVM *vm);
Detaches the current thread from a Java VM. AllJava monitors held by this thread are released. All Java threadswaiting for this thread to die are notified.
As of JDK/JRE 1.2 , the main thread can be detached from the VM.Index 5 in the JavaVM interface functiontable.
vm
: the VM from whichthe current thread will be detached.
Returns JNI_OK
onsuccess; returns a suitable JNI error code (a negative number) onfailure.
jint GetEnv(JavaVM *vm, void **env, jintversion);
Index 6 in the JavaVM interface functiontable.
vm
: The virtual machine instance fromwhich the interface will be retrieved.env
: pointer to the location where theJNI interface pointer for the current thread will be placed.version
: The requested JNIversion.If the current thread is not attached to the VM, sets*env
to NULL
, and returnsJNI_EDETACHED
. If the specified version is notsupported, sets *env
to NULL
, and returnsJNI_EVERSION
. Otherwise, sets *env
to theappropriate interface, and returns JNI_OK
.
JDK/JRE 1.2
聯(lián)系客服