企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
为了说明Invocation interface,我们先来看一个加载java虚拟机并调用Prog.main函数的C程序,Prog类如下: ~~~ public class Prog { public static void main(String[] args) { System.out.println("Hello World " + args[0]); } } ~~~ 以下的C程序invoke.c,用于加载Java虚拟机并调用Prog.main函数。 ~~~ #define _JNI_IMPLEMENTATION_ #include <jni.h> #define PATH_SEPERATOR ";" /* define it to be ':' on Solaris */ #define USER_CLASSPATH "." /* where Prog.class is */ #ifdef __cplusplus extern "C" { #endif void destroy(JNIEnv* env, JavaVM *jvm){ if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionDescribe(env); } (*jvm)->DestroyJavaVM(jvm); } int main() { JNIEnv *env; JavaVM *jvm; jint res; jclass cls; jmethodID mid; jstring jstr; jclass stringClass; jobjectArray args; #ifdef JNI_VERSION_1_2 JavaVMInitArgs vm_args; JavaVMOption options[1]; options[0].optionString = "-Djava.class.path=" USER_CLASSPATH; vm_args.version = 0x00010002; vm_args.options = options; vm_args.nOptions = 1; vm_args.ignoreUnrecognized = JNI_TRUE; /* Create the Java VM */ res = JNI_CreateJavaVM(&jvm, (void**)&env, (void*)&vm_args); #else JDK1_1InitArgs vm_args; char classpath[1024]; vm_args.version = 0x00010001; JNI_GetDefaultJavaVMInitArgs(&vm_args); /* Append USER_CLASSPATH to the default system class path */ sprintf(classpath, "%s%c%s", vm_args.classpath, PATH_SEPERATOR, USER_CLASSPATH); vm_args.classpath = classpath; /* Create the Java VM */ res = JNI_CreateJavaVM(&jvm, &env, &vm_args); #endif /* JNI_VERSION_1_2 */ if (res < 0){ fprintf(stderr, "Can't create Java VM\n"); return 1; } cls = (*env)->FindClass(env, "Prog"); if(!cls){ destroy(env, jvm); return 1; } mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V"); if(!mid){ destroy(env, jvm); return 1; } jstr = (*env)->NewStringUTF(env, " From C!"); if(!jstr){ destroy(env, jvm); return 1; } stringClass = (*env)->FindClass(env, "java/lang/String"); args = (*env)->NewObjectArray(env, 1, stringClass, jstr); if(!args){ destroy(env, jvm); return 1; } (*env)->CallStaticVoidMethod(env, cls, mid, args); destroy(env, jvm); return 0; } #ifdef __cplusplus } #endif ~~~ 以上代码中使用宏来判断JDK版本,并根据版本调用不同的JDK初始化函数,目前最新的已经是JDK_VERSION_1_8了,初始化API为JavaVMInitArgs(与JDK_VERSION_1_2相同)。 当构建的target为1.2,C代码首先创建一个JavaVMInitArgs结构,虚拟机的初始化参数存储在JavaVMOption数组中,你可以使用普通的选项(比如-Djava.class.path=.)或者java命令相关的选项(比如-Xmx64m),设置ignoreUnrecognized数位为JNI_TRUE标识让虚拟忽略其不认识的选项。 在设置完虚拟机初始化结构体之后,C程序调用JNI_CreateJavaVM函数来加载和初始化Java虚拟机,这个函数会有两个输出: * 一个接口指针jvm,指向最新创建的Java虚拟机。 * 当前线程的JNIEnv接口指针env。所有的JNI函数访问都需要通过env。 当JNI_CreateJavaVM函数成功的返回之后,当前的Native线程就已经将自己引导入了Java虚拟机。此时,它就像在执行一个Native方法,因此,它可以发起JNI调用来触发Prog.main函数。 最后程序调用了DestroyJavaVM函数用于卸载虚拟机,不幸的是你不能够在JDK1.1或者JDK1.2中卸载Java虚拟机,因为在这两个版本中,DestroyJavaVM函数会一直返回错误码。运行以上程序将会输出: ~~~ Hello World from C! ~~~