C++调用java类

来源:互联网 发布:数据机房运维常见问题 编辑:程序博客网 时间:2024/05/16 16:05

C++调用Java类

JNI之C++调用Java类

   ——java.lang.String

   为什么要用C++调用Java类?很难回答,写着文章只是觉得JNI很有意思。于是开始编写一段使用VC++在Windows系统里调用java的String类,在C++里调用String类内的一些方法。

JNI已经被开发了很多年,而在我2年多的Java编程时间里从来没有接触过。直到最近研究JVM实现原理才注意到JNI。 JNI既Java Native Interface,Native这个词我见过我认为最恰当的翻译就是原生。原生的意思就是来自系统自己的,原汁原味的东西,例如Win32 API。Java类需要在虚拟机上运行,也就不是原生的,同样.NET Framework也不是原生的。JNI也就是Java原生接口。关于JNI的规范,以及为什么要使用它,它能做些什么,都在http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html里记述着。

      JNI是规范,它规定了虚拟机的接口,而把具体的实现留给开发者。

JVM的实现不是唯一的,目前存在很多种Java虚拟机,Sun Hotspot,IBM JDK,还有HP的,Kaffe等等。最流行的就是Sun的Hotspot,最复杂的就是IBM JDK,这是IBM的一贯作风。本文不讨论JVM的实现,只关注JNI。如果您安装了Sun的JDK,您就能在[JAVA_HOME]\include目录下找到jni.h。这个头文件就是虚拟机的唯一接口,你可以调用它声明的函数创建一个JVM。

   在说明C++调用Java类之前,我想先演示一下如果编写JavaNative Method。

1.编写带有Native方法的Java类

packageorg.colimas.jni.test;

 

public class JniTest{

 

       static {System.loadLibrary("JniTestImpl"); } //JVM调用JniTestImpl.dll

       

       public JniTest(){

       

       }

       //原生方法

       public native void print(String str);

      /**

       *@param args

       */

      public static void main(String[] args) {

            

             JniTest test=new JniTest();

             test.print("hello JVM");//调用原生方法

            

      }

}

2.使用javah生成c语言头文件。

javah -jniorg.colimas.jni.test.JniTest

目录里多了一个org_colimas_jni_test_JniTest.h文件,打开文件,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class org_colimas_jni_test_JniTest */

 

#ifndef_Included_org_colimas_jni_test_JniTest

#define_Included_org_colimas_jni_test_JniTest

#ifdef __cplusplus

extern"C" {

#endif

/*

 * Class:     org_colimas_jni_test_JniTest

 * Method:    print

 * Signature: (Ljava/lang/String;)V

 */

JNIEXPORT void JNICALL Java_org_colimas_jni_test_JniTest_print

  (JNIEnv *, jobject, jstring);

 

#ifdef __cplusplus

}

#endif

#endif

 

其中的Java_org_colimas_jni_test_JniTest_print就是JniTest类里面的print原生方法的C语言声明。

3.编写C代码实现原生方法print

#include <jni.h>

#include"org_colimas_jni_test_JniTest.h" //javah生成的头文件

#include <stdio.h>

 

JNIEXPORT void JNICALL Java_org_colimas_jni_test_JniTest_print

  (JNIEnv *env, jobjectobject,jstring str)

{

   //获得字符串

   constchar *txt=(*env)->GetStringUTFChars(env,str,0);

   printf("%s\n",txt); //打印到控制台

   return;

}

 

参数JNIEnv *env,是JNI里最重要的变量。Java.exe创建JVM,之后JVM生成一个env,该env相当于JVM内的Session,可以完成创建Java对象,调用类方法,获得类的属性等等。

在这里env将方法的参数Str从JNI的jstring类型转换为常数char数组。

4.编译

cl  /Ic:\j2sdk1.4.2_10\include/Ic:\j2sdk1.4.2_10\include\win32 /c JniTestImpl.c

 

5.连接为DLL

link /dllJniTestImpl.obj

6.设置PATH

setPATH=C:\MyProject\Colimas\CD\JNI\MyJNI;%PATH%

7.运行

javaorg.colimas.jni.test.JniTest

返回结果

hello JVM

结束

   以上是实现Java原生方法的开发过程,下面进入正题,使用C++调用Java的java.lang.String类。

1.      Object类出创建JVM。

使用Java类之前必须要创建JVM环境。JDK由java.exe来完成。本文有Object类的静态方法BeginJVM来创建,用EndJVM来关闭。

创建JVM之后会在创建2个变量,分别是JNIEnv* env和JavaVM* jvm,JNIEnv上文已经说明,JavaVM,顾名思义,代表Java虚拟机,用它来关闭JVM。

Object类的头文件

 

#include"jni.h"

class Object 

{

public:

      static bool BeginJVM();

      static bool EndJVM();

      Object();

      virtual ~Object();

 

protected:

       static JNIEnv* env;

       static JavaVM* jvm;

};

 

object.cpp代码

#include"stdafx.h"

#include"JavaClasses.h"

#include"Object.h"

 

Object::Object()

{}

 

Object::~Object()

{}

 

JNIEnv*Object::env=NULL;

JavaVM*Object::jvm=NULL;

//创建JVM

boolObject::BeginJVM()

{

      JavaVMOption options[3];

      JavaVMInitArgs vm_args;

//各种参数

      options[0].optionString="-Xmx128m";

      options[1].optionString="-Verbose:gc";

      options[2].optionString="-Djava.class.path=.";

 

      vm_args.version=JNI_VERSION_1_2;

      vm_args.options=options;

      vm_args.nOptions=3;

//创建JVM,获得jvm和env

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

      return true;

}

 

bool Object::EndJVM()

{

//关闭JVM

      jvm->DestroyJavaVM();

      return true;

}

2.      C++的String类调用java.lang.String类方法

编写C++版的String类,调用java String类方法。调用的方法如下:

      String replaceAll(String regex, String replacement);

      boolean endsWith(String str);

      int indexOf(String str);

      int compareTo(String anotherString);

      char charAt(int i);

 

String的头文件:

class String  :public Object

{

public:

//与要调用的Java方法名一致。

      const char * replaceAll(char *regex,char*replacement);

      bool endsWith(char * str);

      int indexOf(char * str);

      int compareTo(char *anotherString);

      char charAt(int i);

      String(char *str);

      virtual ~String();

 

};

 

实现:

 

#include"stdafx.h"

#include"String.h"

#include"jni.h"

 

using namespace std;

jclass clazz;    //全局变量,用来传递class

jobject object;  //全局变量,用来传递object

String::String(char*str)

{

    jstring jstr;

 

      if (Object::env ==NULL)

      {

             cout << "JVM is notcreated" << endl;

             exit(-1);

      }

      //获得java.lang.String类

      clazz=Object::env->FindClass("java/lang/String");

      if (clazz ==0 ){

             cout << "Class is notfound" << endl;

             exit(-1);

      }

      //获得String(String str)构造体

      jmethodID mid=Object::env->GetMethodID(clazz,"<init>","(Ljava/lang/String;)V");

      if (mid==0){

             cerr<< "GetMethodIDError for class" << endl;

             exit(-1);

      }

//江字符串封装为jstring。

    jstr = Object::env->NewStringUTF(str);

    if (jstr == 0) {

             cerr << "Out ofmemory" <<endl;

        exit(-1);

    }

 

      cout << "invoking method"<< endl;

//创建一个java.lang.String对象。

      object=Object::env->NewObject(clazz,mid,jstr);

 

}

 

String::~String()

{}

 

char String::charAt(inti)

{

      if (Object::env ==NULL)

      {

             cout << "JVM is notcreated" << endl;

             exit(-1);

      }

      if (clazz ==0 ){

             cout << "Class is notfound" << endl;

             exit(-1);

      }

      if (object ==0 ){

             cout << "String objectis not created" << endl;

             exit(-1);

      }

      jmethodID mid;

      //获得charAt方法,(I)C表示 参数为int型,返回char型。详细参见JNI规范

      mid=Object::env->GetMethodID(clazz,"charAt", "(I)C");

      if (mid==0){

             cerr<< "GetMethodIDError for class" << endl;

             exit(-1);

      }

      jint ji=i;

      cout << "invoking method"<< endl;

//调用charAt

      jchar z=Object::env->CallCharMethod(object,mid,i);

//返回结果。

      return z;

 

}

 

intString::compareTo(char *anotherString)

{

      if (Object::env ==NULL)

      {

             cout << "JVM is notcreated" << endl;

             exit(-1);

      }

      if (clazz ==0 ){

             cout << "Class is notfound" << endl;

             exit(-1);

      }

      if (object ==0 ){

             cout << "String objectis not created" << endl;

             exit(-1);

      }

      jmethodID mid;

//(Ljava/lang/String;)I表示参数为java.lang.String,返回int

      mid=Object::env->GetMethodID(clazz,"compareTo","(Ljava/lang/String;)I");

      if (mid==0){

             cerr<< "GetMethodIDError for class" << endl;

             exit(-1);

      }

      jstring jstr =Object::env->NewStringUTF(anotherString);

      cout << "invoking method"<< endl;

//调用方法

jintz=Object::env->CallIntMethod(object,mid,jstr);

//返回结果

      return z;

}

 

intString::indexOf(char *str)

{

      if (Object::env ==NULL)

      {

             cout << "JVM is notcreated" << endl;

             exit(-1);

      }

      if (clazz ==0 ){

             cout << "Class is notfound" << endl;

             exit(-1);

      }

      if (object ==0 ){

             cout << "String objectis not created" << endl;

             exit(-1);

      }

      jmethodID mid;

 

      mid=Object::env->GetMethodID(clazz,"indexOf","(Ljava/lang/String;)I");

      if (mid==0){

             cerr<< "GetMethodIDError for class" << endl;

             exit(-1);

      }

      jstring jstr =Object::env->NewStringUTF(str);

      cout << "invoking method"<< endl;

      jint z=Object::env->CallIntMethod(object,mid,jstr);

 

      return z;

}

 

boolString::endsWith(char *str)

{

      if (Object::env ==NULL)

      {

             cout << "JVM is notcreated" << endl;

             exit(-1);

      }

      if (clazz ==0 ){

             cout << "Class is notfound" << endl;

             exit(-1);

      }

      if (object ==0 ){

             cout << "String objectis not created" << endl;

             exit(-1);

      }

      jmethodID mid;

 

      mid=Object::env->GetMethodID(clazz,"endsWith","(Ljava/lang/String;)Z");

      if (mid==0){

             cerr<< "GetMethodIDError for class" << endl;

             exit(-1);

      }

      jstring jstr =Object::env->NewStringUTF(str);

      cout << "invoking method"<< endl;

      boolz=Object::env->CallBooleanMethod(object,mid,jstr);

     

      return z;

}

 

const char *String::replaceAll(char *regex, char *replacement)

{

 

 

      if (Object::env ==NULL)

      {

             cout << "JVM is notcreated" << endl;

             exit(-1);

      }

      if (clazz ==0 ){

             cout << "Class is notfound" << endl;

             exit(-1);

      }

      if (object ==0 ){

             cout << "String objectis not created" << endl;

             exit(-1);

      }

      jmethodID mid;

 

      mid=Object::env->GetMethodID(clazz,"replaceAll","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

      if (mid==0){

             cerr<< "GetMethodIDError for class" << endl;

             exit(-1);

      }

      jvalue array[2];

      jstring jreg =Object::env->NewStringUTF(regex);

      jstring jstr = Object::env->NewStringUTF(replacement);

      array[0].l=jreg;

      array[1].l=jstr;

      cout << "invoking method"<< endl;

//传入参数,调用replaceAll方法

      jobjectz=Object::env->CallObjectMethodA(object,mid,array);

      const char*result=Object::env->GetStringUTFChars((jstring)z, 0);

      return (const char *)result;

}

 

3.测试

 

编写测试代码

using namespace std;

 

int _tmain(int argc,TCHAR* argv[], TCHAR* envp[])

{

      int nRetCode = 0;

 

      if (!AfxWinInit(::GetModuleHandle(NULL),NULL, ::GetCommandLine(), 0))

      {

             cerr << _T("Fatal Error:MFC initialization failed") << endl;

             nRetCode = 1;

      }

      else

      {

//创建JVM

             Object::BeginJVM();

            

             String test("hello");

             //调用replaceAll

             const char*result=test.replaceAll("l","z");

             //返回结果

             cout<< result <<endl;

             //关闭JVM

             Object::EndJVM();

      }

 

      return nRetCode;

}

 

 

 

4.运行

编译需要 jni.h和jvm.lib文件。

jni.h在[JAVA_HOME]\include

jvm.lib在[JAVA_HOME]\lib

 

运行需要jvm.dll

jvm.dll在[JAVA_HOME]\jre\bin\client

运行结果如下:

invoking method

invoking method

hezzo

Press any key tocontinue

     

   尽管本文的代码很有意思,但我还没有想到有什么价值,以及应用到实际项目中的理由。

 

 

 

 

为什么要自己写C++程序加载Java虚拟机

通常情况下,我们完成了Java类的开发后,都是通过脚本调用Javajava.exe或者javaw.exe来启动Java虚拟机的,但在某些情况下,我们需要用C++程序来自行加载Java虚拟机运行我们的java程序,例如:

1 windows下面,你想把java程序做成一个后台服务,就像tomcat那样,这样就可以让windows操作系统帮你管理java程序的启动和停止了。

4<span style="font-size:12.0pt;line-height:150%;font-family:"Times New Roman" ''","serif";mso-ascii-font-family:="" "times="" new="" roman";mso-fareast-font-family:"times="" roman\0027\0027\0027";="" mso-hansi-font-family:"times="" roman";color:#666666;mso-font-kerning:0pt'="">、 你在开发象IE这样的程序,在必要的时候才启动虚拟机运行一段Java程序

本文就教你如何做到这一点。

C++加载虚拟机的两种方法比较

加载虚拟机可以采用以下两种方法:

1 用创建子进程的方法调用java.exe来启动,在windows下面可以用CreateProcess方法,在Linux下面可以用execvp方法,调用的方式和用脚本调用差不多,这种方法比较简单我就不详细介绍了,详细的方式可以参考开源项目 Java Service Wrapper。用创建子进程的方式用以下优点:

1)       开发简单,兼容性好,对于java虚拟机的不同版本调用方式都是一样的

2)       创建出来的java进程和C++程序的进程分离,不会相互影响,你不会因为C程序出现什么内存错误崩溃导致java进程也一起完蛋(当然分离进程也带来了其他问题,详见我后面的分析)

但是我不太喜欢这种方法,因为有以下缺点:

1  生成分离的java进程后,在系统里会看到另外一个java.exe的进程,当启动了很多这样的进程时,你会看到很多名称为java的进程,你无法区分哪个是哪个。

2  生成了分离的Java 进程后,你就不好对它进行控制,比如说要关闭它,如果直接killjava进程,可能java进程里面一些关闭时需要做的清理工作还来不及做。如果想让java程序执行清理工作再退出,你就需要建立和java程序之间的通讯机制,以向java程序发出退出的消息,这通常还需要在java程序里面加载专门的类,以及需要java程序的开发人员进行相关的接口开发工作。

2 加载java虚拟机的另外一种方法是加载jvm的动态库,并通过动态库的接口来在本进程内启动java虚拟机。我更加喜欢这种方法,因为这种方法可以带来很多好处:

1)       你可以更好地对java虚拟机进行有效地控制,java程序不需要加载专门的类库,你只需要调用不同的java类方法就可以控制java程序的启动、停止等操作

2)       不会产生额外的java进程,在系统进程中进程名称是你C++主程序的名字,你可以在系统进程列表中很清楚地区分每个进程

当然这种方法也有缺点,但我认为不是大问题:

1)       由于java虚拟机在进程内部加载,如果主程序写得不好而崩溃会导致java程序也一起终止

2)       动态库接口得开发要稍微难一点,需要你了解jvm动态库的接口,不过待会儿你就会看到,这也不是很困难的事情

3)       jdk不同版本的接口稍微有一点区别,以后可能也会发生变化,你可能得对不同的jdk版本修改一下C程序,但相对来说jvm的兼容性应该是可以信任的

 

 

 

 加载jvm动态库的方法介绍

下面就详细介绍一下用C++程序加载动态库的方法,我将分别针对windows平台和linux/unix平台分别进行介绍:

windows平台的加载方法

windows平台下jdkjava虚拟机动态库为jvm.dll,位于:

%JAVA_HOME%/jre/bin/client/jvm.dll

%JAVA_HOME%/jre/bin/server/jvm.dll

Jvm动态库有clientserver两个版本,分别针对桌面应用和服务器应用做了相应的优化,client版本加载速度较快,server版本加载速度较慢但运行起来较快。

虚拟机加载可按照以下步骤进行:

1  装载jvm动态库

2  查找JNI_CreateJavaVM接口

3  设置JVM启动参数,调用JNI_CreateJavaVM接口启动虚拟机

4  查找启动类,设置命令行参数,设置窗口输出重导向文件

5  调用启动类的启动方法启动java程序

6  要停止Java程序运行时,调用java类的停止方法即可

 下面的示例代码就说明了一个简单的加载过程

 typedef jint(JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);

bool setStream(JNIEnv *env, const char* pszFileName, const char*pszMethod);

 //启动java虚拟机方法

bool startJvm()

{

    //jvm动态库的路径

    const char szJvmPath[] ="c:\\jdk1.5.0_01\\jre\\bin\\server\\jvm.dll";

   

    //java虚拟机的启动参数,每个参数写一项,不能合在一起写

    int nOptionCount = 2;

    JavaVMOption options[2];

    options[1].optionString ="-Xmx256M";

//设置classpath

    options[0].optionString ="-Djava.class.path=./Test.jar;./Test1.jar";

   

    JavaVMInitArgs vm_args;

    vm_args.version =JNI_VERSION_1_4;

    vm_args.options = options;

    vm_args.nOptions = nOptionCount;

    vm_args.ignoreUnrecognized =JNI_TRUE;

   

    //启动类,注意分割符是/,例如启动类test.JTest应该写成test/JTest

    const char szStartClass[] ="test/JTest";

    //启动方法,通常是main函数,你也可以设定成其他函数

    const char szStartMethod[] ="main";

   

    //重导向文件

    const char szStdoutFileName ="stdout.txt";

    const char szStderrFileName ="stderr.txt";

   

    //java程序的命令行参数

    int nParamCount = 2;

    const char *szParams[2] ={"arg1","arg2"};

   

    //加载JVM

    HINSTANCE jvmDll =LoadLibrary(szJvmPath);

    if (jvmDll == NULL)

    {

          printf("加载JVM动态库错误。%l",::GetLastError());

          returnfalse;

    }

//查找JNI_CreateJavaVM过程。

    JNICREATEPROC jvmCreateProc =(JNICREATEPROC)GetProcAddress(jvmDll, "JNI_CreateJavaVM");

    if (jvmCreateProc == NULL)

    {

          FreeLibrary(jvmDll);

          printf("查找JNI_CreateJavaVM过程错误。%l",::GetLastError());

          returnfalse;

    }

   

    //创建JVM

    JNIEnv *env;

    jint r =(jvmCreateProc)(&jvm, (void **)&env, &vm_args);

    if (r < 0 || jvm == NULL ||env == NULL)

    {

          FreeLibrary(jvmDll);

          printf("创建JVM发生错误。");

          returnfalse;

    }

   

    //重导向stdout, stderr到输出文件

   

    if (!setStream(env,szStdoutFileName, "setOut"))

    {

        printf("设置stdout输出文件失败");

        return false;

    }

   

    if (!setStream(env,szStderrFileName, "setErr"))

    {

        printf("设置stderr输出文件失败");

        return false;

    }

   

    //加载启动类。

    jclass serviceClass =env->FindClass(szStartClass);

    if (env->ExceptionCheck() == JNI_TRUE ||serviceClass == NULL)

    {

          env->ExceptionDescribe();

          env->ExceptionClear();

          FreeLibrary(jvmDll);

          printf("加载启动类失败。");

          returnfalse;

    }

    

    //启动方法

    jmethodID mid =env->GetStaticMethodID(serviceClass, szStartMethod ,"([Ljava/lang/String;)V");

    if (env->ExceptionCheck() ==JNI_TRUE || mid == NULL)

    {

          env->ExceptionDescribe();

          env->ExceptionClear();

          FreeLibrary(jvmDll);

          printf("查找启动方法失败。");

          returnfalse;

    }

   

    //查找String类。

    jclass stringClass =env->FindClass("java/lang/String");

    if (env->ExceptionCheck() ==JNI_TRUE || stringClass == NULL)

    {

          env->ExceptionDescribe();

          env->ExceptionClear();

          FreeLibrary(jvmDll);

          printf("查找String类失败。");

          returnfalse;

    }

   

    jstring jstr;

    for (int i=0; i<nParamCount;i++)

    {

        jstr =env->NewStringUTF(szParams[i]);

        if (jstr == 0) {

            printf("分配String失败\n");

            if (env->ExceptionOccurred()){

                env->ExceptionDescribe();

                env->ExceptionClear();

            }

            return false;

        }

          env->SetObjectArrayElement(args,i, jstr);

          if(env->ExceptionCheck() == JNI_TRUE)

          {

            printf("设置参数失败\n");

            if(env->ExceptionOccurred()) {

                env->ExceptionDescribe();

                env->ExceptionClear();

            }

            return false;

          }

    }

   

    //调用启动类的启动方法启动Java程序

   env->CallStaticVoidMethod(serviceClass, mid, parameterArray);

    if (env->ExceptionCheck() ==JNI_TRUE)

    {

          env->ExceptionDescribe();

          env->ExceptionClear();

          FreeLibrary(jvmDll);

      return false;

    }

   return true;

}

  //设置输出流的方法

bool setStream(JNIEnv *env, const char* pszFileName, const char*pszMethod)

{

       int pBufferSize = 1024;

       char* pBuffer = newchar[pBufferSize];

              //创建字符串对象。

       jstring pathString =env->NewStringUTF(pszFileName);

       if (env->ExceptionCheck()== JNI_TRUE || pathString == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("创建字符串失败。");

              return false;

       }

              //查找FileOutputStream类。

    jclass fileOutputStreamClass =env->FindClass("java/io/FileOutputStream");

       if (env->ExceptionCheck()== JNI_TRUE || fileOutputStreamClass == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("查找FileOutputStream类失败。");

              return false;

       }

       //查找FileOutputStream类构造方法。

    jmethodIDfileOutputStreamConstructor = env->GetMethodID(fileOutputStreamClass,"<init>", "(Ljava/lang/String;)V");

       if (env->ExceptionCheck()== JNI_TRUE || fileOutputStreamConstructor == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("查找FileOutputStream类构造方法失败。");

              return false;

       }

       //创建FileOutputStream类的对象。

    jobject fileOutputStream = env->NewObject(fileOutputStreamClass,fileOutputStreamConstructor, pathString);

       if (env->ExceptionCheck()== JNI_TRUE || fileOutputStream == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("创建FileOutputStream类的对象失败。");

              return false;

       }

       //查找PrintStream类。

    jclass printStreamClass =env->FindClass("java/io/PrintStream");

       if (env->ExceptionCheck()== JNI_TRUE || printStreamClass == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("查找PrintStream类失败。");

              return false;

       }

       //查找PrintStream类构造方法。

    jmethodID printStreamConstructor= env->GetMethodID(printStreamClass, "<init>","(Ljava/io/OutputStream;)V");

       if (env->ExceptionCheck()== JNI_TRUE || printStreamConstructor == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("查找PrintStream类构造方法失败。");

              return false;

       }

       //创建PrintStream类的对象。

    jobject printStream =env->NewObject(printStreamClass, printStreamConstructor, fileOutputStream);

       if (env->ExceptionCheck()== JNI_TRUE || printStream == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("创建PrintStream类的对象失败。");

              return false;

       }

 

       //查找System类。

    jclass systemClass =env->FindClass("java/lang/System");

       if (env->ExceptionCheck()== JNI_TRUE || systemClass == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf( "查找System类失败。");

              return false;

       }

       //查找System类设置方法。

    jmethodID setStreamMethod =env->GetStaticMethodID(systemClass, pszMethod,"(Ljava/io/PrintStream;)V");

       if (env->ExceptionCheck()== JNI_TRUE || setStreamMethod == NULL)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("查找System类设置方法失败。");

              return false;

       }

       //设置System类的流。

       env->CallStaticVoidMethod(systemClass,setStreamMethod, printStream);

       if (env->ExceptionCheck()== JNI_TRUE)

       {

              env->ExceptionDescribe();

              env->ExceptionClear();

              printf("设置System类的流失败。");

              return false;

       }

}

 Linux平台的加载方法

Linux平台下的虚拟机的加载方法跟windows平台基本一致,不同的地方仅在于加载动态库的方法不同,在linux平台的JDK中,jvm动态库所在的路径为

$JAVA_HOME/jre/lib/i386/client/libjvm.so

$JAVA_HOME/jre/lib/i386/server/libjvm.so

Linux下装载动态库的示例代码如下:

#include <jni.h>

#include <stdlib.h>

#include <dlfcn.h>

typedef void* (*JNICREATEPROC)(JavaVM **, JNIEnv **, void *);

bool startJVM() {

    JNIEnv *env;

    JavaVM *jvm;

    jclass cls;

    jmethodID mid;

    jobjectArray args;

    //jvm动态库的路径

    const char szJvmPath[] ="/usr/jdk1.5.0_01/jre/lib/i386/server/libjvm.so";

    //启动类

    const char szStartClass[] ="test/JTest";

    //启动方法

    const char szStartMethod[] ="main";

   

    //Java启动参数

    int nOptionCount = 2;

    JavaVMOption options[2];

    options[1].optionString ="-Xmx256M";

    options[0].optionString ="-Djava.class.path=./Test.jar;./Test1.jar";

    JavaVMInitArgs vm_args;

    vm_args.version =JNI_VERSION_1_4;

    vm_args.options = options;

    vm_args.nOptions = nOptionCount;

    vm_args.ignoreUnrecognized =JNI_TRUE;

    //命令行参数

    int nParamCount = 2;

    const char *szParams[2] ={"arg1","arg2"};

    //装载动态库

    void* lib_handle = 0;

    lib_handle = dlopen(szJvmPath,RTLD_NOW);

    if (!lib_handle)

    {

       fprintf(stderr, "dlopenfailed\n");

       return false;

    }

  

    JNICREATEPROC lib_func = 0;

    //查找JNI_CreateJavaVM过程

    lib_func =(JNICREATEPROC)dlsym(lib_handle, "JNI_CreateJavaVM");

    lib_func(&jvm,&env,&vm_args);

    //后面与windows平台处理流程完全一样

    cls =env->FindClass(szStartClass);

    if (cls == 0) {

        fprintf(stderr,"Can''''t find class:%s\n",szStartClass);

        if(env->ExceptionOccurred()) {

            env->ExceptionDescribe();

        }

        return false;

    }

    mid =env->GetStaticMethodID(cls,szStartMethod,"([Ljava/lang/String;)V");

    if (mid == 0) {

        fprintf(stderr,"Can''''t find Method:%s\n",szStartMethod);

        if(env->ExceptionOccurred()) {

             env->ExceptionDescribe();

        }

        return false;

    }

    jclass stringClass =env->FindClass("java/lang/String");

       if (env->ExceptionCheck()== JNI_TRUE || stringClass == NULL)

       {

              fprintf(stderr,"find String class error");

if (env->ExceptionOccurred()) {

            env->ExceptionDescribe();

        }

        return false;

       }

    args =env->NewObjectArray(nParamCount, stringClass, NULL);

    if (args == 0) {

        fprintf(stderr, "Out ofmemory\n");

        if(env->ExceptionOccurred()) {

             env->ExceptionDescribe();

        }

        return false;

    }

   

    jstring jstr;

    for (int i=0; i<nParamCount;i++)

    {

        jstr =env->NewStringUTF(szParams[i]);

        if (jstr == 0) {

            fprintf(stderr,"Out of memory\n");

            if(env->ExceptionOccurred()) {

                env->ExceptionDescribe();

            }

            jvm->DestroyJavaVM();

            return false;

        }

              env->SetObjectArrayElement(args,i, jstr);

              if(env->ExceptionCheck() == JNI_TRUE)

              {

            fprintf(stderr,"set param error\n");

            if(env->ExceptionOccurred()) {

                env->ExceptionDescribe();

            }

            jvm->DestroyJavaVM();

            return -1;

              }

    }

   

    env->CallStaticVoidMethod(cls,mid, args);

    if (env->ExceptionOccurred()){

        env->ExceptionDescribe();

         return false;

    }

    return true;

}

参考资料

1 用创建子进程方式启动Java虚拟机的具体方法,可参考开源项目 Java Service Wrapperhttp://wrapper.tanukisoftware.org

2 关于jvm动态库JNI方法的具体说明,参加SUN网站关于JNI的说明http://java.sun.com/j2se/1.4.2/docs/guide/jni/

版权声明

本文为fita个人原创,未经本人允许不得转载、摘抄

 

原创粉丝点击