C++調用JVM.dll運行Java程序,JNI實戰簡例,精簡JRE實戰。

精簡一下JRE,實現C++和JAVA混合編程:

JRE目錄:

jre/bin/server/jvm.dll

jre/bin/java.dll

jre/bin/verify.dll

jre/bin/zip.dll

jre/lib/rt.jar

下面是Java端測試內容:

jre/Test/com/hwb/Hello.java

package com.hwb;

//
public class Hello {
    //
	public static void main(String[] args) {
		System.out.println("Hello Java World!");
	}
}

jre/Test/META-INF/MANIFEST.MF

Manifest-Version: 1.0
Created-By: 1.8.0_161 (Oracle Corporation)
Main-Class: com.hwb.Hello

jre/Test/Test.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

//
public class Test {
    
    //
    public void Hello(String message) {
        System.out.println("Hello in class Test, From c++ " + message);
    }

    //
	public static void main(String[] args) {
        //
		System.out.println("Hello Java World!");
        //
        //得到模板
        TestFunction func = new TestFunction();
        //
        Map<String, Object> params = new HashMap<String, Object>();
        //測試參數
        params.put("a", 1L);
        params.put("b", 2);
        params.put("c",  new Long[]{1L,2L,3L});
        //執行函數
        Map<String,Object> output = func.apply(params);
        //遍歷結果
        for(Map.Entry<String, Object> entry : output.entrySet()){
            String mapKey = entry.getKey();
            Object mapValue = entry.getValue();
            System.out.println(mapKey + ":" + mapValue);
        }
	}
}

jre/Test/TestFunction.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

//測試jdk1.8的Function特性
public class TestFunction implements Function<Map<String, Object>, Map<String, Object>> {

    public TestFunction() {
        //
    }

    //重寫apply實現
    public Map<String, Object> apply(Map<String, Object> param) {
        HashMap output = new HashMap();
        Long a = (Long)param.get("a");
        int b = (Integer)param.getOrDefault("b", 0);
        if (output != null ) {
            output.put("output", a+b); // Sum
            return output;
        }

        return new HashMap();
    }
}

jre/Test/run.bat

@echo off

set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_161
set PATH=%JAVA_HOME%/bin;%PATH%
::
echo "--------------------java jar test----------------------"
::
javac com/hwb/Hello.java
java com.hwb.Hello
::
jar -cvfm Hello.jar META-INF/MANIFEST.MF com/hwb/Hello.class
java -jar Hello.jar

echo "------------------java Function test------------------------"

::javac TestFunction.java
::
javac Test.java
::
java Test

pause

實戰一下JNI編程:

//
#include "Java/jni.h"
#include <windows.h>
#include <Shlwapi.h>  
#pragma comment(lib,"Shlwapi.lib")
//
#include <iostream>
using namespace std;

//前置定義
bool CreateJvmAndTest();

//入口
int main(int argc, char* argv[])
{
    cout << "Hello C++ JVM..." << endl;
    //
    CreateJvmAndTest();
    //getchar();
    return 0;
}

//構造函數
typedef jint(JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);

//啓動java虛擬機
bool CreateJvmAndTest()
{
    char exepath[1024] = { 0 };
    GetModuleFileNameA(nullptr, exepath, 1024);
    PathRemoveFileSpecA(exepath);
    //獲取jvm動態庫的路徑
    std::string jvmPath = std::string(exepath) + "\\..\\..\\jre\\bin\\server\\jvm.dll";
    //
    //java虛擬機啓動時接收的參數,每個參數單獨一項
    int nOptionCount = 2;
    JavaVMOption vmOption[2];
    //設置JVM最大允許分配的堆內存,按需分配!!!
    vmOption[0].optionString = (char*)"-Xmx256M";
    //設置classpath
    std::string classpath = std::string("-Djava.class.path=.\\;");
    classpath += (std::string(exepath) + ";");
    classpath += (std::string(exepath) + std::string("\\..\\..\\jre\\Test\\Hello.jar;"));
    classpath += (std::string(exepath) + std::string("\\..\\..\\jre\\Test\\;"));
    vmOption[1].optionString = (char*)classpath.c_str();

    JavaVMInitArgs vmInitArgs;
    //
    vmInitArgs.version = JNI_VERSION_1_8;//JDK1.8版本
    vmInitArgs.options = vmOption;
    vmInitArgs.nOptions = nOptionCount;
    //
    // 忽略無法識別jvm的情況
    vmInitArgs.ignoreUnrecognized = JNI_TRUE;

    //設置啓動類,注意分隔符爲"/"
    const char startClass[] = "com/hwb/Hello";
    //啓動方法,一般是main函數,當然可以設置成其他函數
    const char startMethod[] = "main";
    
    //加載JVM動態庫
    HINSTANCE jvmDLL = ::LoadLibraryA(jvmPath.c_str()); //加載失敗的話:注意如果是64位jvm,就需要工程也是x64
    if (jvmDLL == NULL)
    {
        cout << "加載JVM動態庫錯誤" + ::GetLastError() << endl;
        return false;
    }

    //獲取JVM函數地址
    JNICREATEPROC jvmProcAddress = (JNICREATEPROC)GetProcAddress(jvmDLL, "JNI_CreateJavaVM");
    if (jvmDLL == NULL)
    {
        FreeLibrary(jvmDLL);
        cout << "加載JVM動態庫錯誤" + ::GetLastError() << endl;
        return false;
    }

    //創建JVM
    JNIEnv *env = nullptr;
    JavaVM *jvm = nullptr;
    jint jvmProc = (jvmProcAddress)(&jvm, (void **)&env, &vmInitArgs);
    if (jvmProc < 0 || jvm == nullptr || env == nullptr)
    {
        FreeLibrary(jvmDLL);
        cout << "創建JVM錯誤" + ::GetLastError() << endl;
        return false;
    }

    //加載啓動類
    jclass mainclass = env->FindClass(startClass);
    if (env->ExceptionCheck() == JNI_TRUE || mainclass == nullptr)
    {
        env->ExceptionDescribe();
        env->ExceptionClear();
        FreeLibrary(jvmDLL);
        cout << "加載啓動類失敗" << endl;
        return false;
    }

    //加載 main 啓動方法
    jmethodID methodID = env->GetStaticMethodID(mainclass, startMethod, "([Ljava/lang/String;)V");
    if (env->ExceptionCheck() == JNI_TRUE || methodID == nullptr)
    {
        env->ExceptionDescribe();
        env->ExceptionClear();
        FreeLibrary(jvmDLL);
        cout << "加載啓動方法失敗" << endl;
        return false;
    }

    cout << "開始執行" << endl;
    env->CallStaticVoidMethod(mainclass, methodID, nullptr);
    cout << "執行結束" << endl;

    //測試JDK1.8函數編程
    jclass funcClass = env->FindClass("Test");
    if (env->ExceptionCheck() == JNI_TRUE || funcClass == nullptr)
    {
        env->ExceptionDescribe();
        env->ExceptionClear();
        FreeLibrary(jvmDLL);
        cout << "加載Function類失敗" << endl;
        return false;
    }

    //加載 main 啓動方法
    jmethodID funcMethodID = env->GetStaticMethodID(funcClass, startMethod, "([Ljava/lang/String;)V");
    if (env->ExceptionCheck() == JNI_TRUE || funcMethodID == nullptr)
    {
        env->ExceptionDescribe();
        env->ExceptionClear();
        FreeLibrary(jvmDLL);
        cout << "加載啓動方法失敗" << endl;
        return false;
    }

    cout << "開始執行" << endl;
    env->CallStaticVoidMethod(funcClass, funcMethodID, nullptr);
    cout << "執行結束" << endl;

    cout << "開始執行類對象方法" << endl;
    //調用成員方法
    jobject string_object = env->AllocObject(funcClass);//創建類對象
    //
    jmethodID paramMethodID = env->GetMethodID(funcClass, "Hello", "(Ljava/lang/String;)V");//查找類方法【void Hello(String msg)】
    //
    jstring param = env->NewStringUTF("hello");
    env->CallVoidMethod(string_object, paramMethodID, param);//執行對象方法
    //
    cout << "執行結束類對象方法" << endl;


    //jvm釋放
    jvm->DestroyJavaVM();
    FreeLibrary(jvmDLL);

    return true;
}


運行結果:

Hello C++ JVM...
開始執行
Hello Java World!
執行結束
開始執行
Hello Java World!
output:3
執行結束
開始執行類對象方法
Hello in class Test, From c++ hello
執行結束類對象方法

over......

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章