7.4.3 在C/C++程序中启动Java虚拟机

上面介绍的这两个使用JNI的场景都是以Java程序为主体的。用户使用的是Java程序,只是程序的部分组件由原生代码来实现。下面介绍的第三个场景以C/C++程序为主体,把Java虚拟机嵌入到原生代码中。通过这种方式,可以在C/C++程序中调用由Java编写的组件。实际上,Java虚拟机本身是通过原生代码来实现的,要在C/C++程序中调用并非难事。在下面的示例中,C++程序需要获取一个网页的内容之后再进行处理。由于Java程序中包含的网络相关的类库比较丰富,获取网页的功能由Java程序来实现,而对网页内容的处理则由C++代码来完成。对此,创建了一个Java类com.java7book.chapter7.jni.WebPageDownloader,其中的静态方法getContent用来根据网页的URL返回其中的内容。在C++程序中启动Java虚拟机如代码清单7-22所示,方法JNI_CreateJavaVM用来创建并启动一个Java虚拟机。在创建时需要提供虚拟机的启动参数。这里只提供了Java类文件所在的路径,用于查找所需的Java类。Java虚拟机创建成功之后,JavaVM表示虚拟机对象,可以利用JNIEnv中的方法来查找Java类并调用其中的方法。在使用完虚拟机之后,需要通过DestroyJavaVM方法来销毁虚拟机。在链接C++代码时需要把JDK的lib目录添加到搜索路径中。

代码清单7-22 在C++程序中启动Java虚拟机


include<jni.h>

int main()

{

JNIEnv*env;

JavaVM*jvm;

JavaVMInitArgs vm_args;

JavaVMOption options[1];

options[0].optionString="-Djava.class.path=C:\java7\code\chapter7\bin";

vm_args.version=JNI_VERSION_1_6;

vm_args.options=options;

vm_args.nOptions=1;

vm_args.ignoreUnrecognized=0;

jint res;

res=JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args);

if(res<0)

{

return res;

}

jclass clsDownloader=env->FindClass("com/java7book/chapter7/jni/WebPageDownloader");

jmethodID midGetContent=env->GetStaticMethodID(clsDownloader,"getContent","(Ljava/lang/String;)Ljava/lang/String;");

jstring content=(jstring)env->CallStaticObjectMethod(clsDownloader, midGetContent, env->NewStringUTF("http://www.baidu.com"));

if(env->ExceptionOccurred())

{

printf("Error occurs when downloading content.");

jvm->DestroyJavaVM();

return-1;

}

const char*text_str=env->GetStringUTFChars(content, NULL);

printf(text_str);

jvm->DestroyJavaVM();

}


上面的代码也说明了C++代码对Java代码中产生的异常的处理方式。在C++代码中,可以通过JNIEnv中的ExceptionOccurred方法来检查Java代码中是否产生了异常,如果产生了异常,那么会执行相应的异常处理逻辑。