C++调用JVM.dll运行Java程序,JNI实战简例,精简JRE实战

Posted 跨链技术践行者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

1
2
3
4
5
6
7
8
9

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

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>>
    private static final String INPUT_VALUE = "input";
    private static final String INPUT_STEP = "step";
    private static final String INPUT_OFFSETS = "offsets";
    private static final String INPUT_REVERSE = "reverse";
    private static final String INPUT_BASE = "base";
    private static final String OUTPUT_ISPASS = "isPass";
    private static final String OUTPUT_RELEASE = "toRelease";

    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;
        else
            output.put("output", 0);
            return output;
       
   

jre/Test/run.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

@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 PlanTemplateAlgorithm.java
::
javac Test.java
::
java Test

pause

实战一下JNI编程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

//
#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
执行结束类对象方法

以上是关于C++调用JVM.dll运行Java程序,JNI实战简例,精简JRE实战的主要内容,如果未能解决你的问题,请参考以下文章

来自 JNI_CreateJavaVM (jvm.dll) 的异常 0xC0000005

JVM原理和性能调优

Java程序通过JNI调用C++程序的方法

JVM

java - 来自JNI_CreateJavaVM(jvm.dll)的异常0xC0000005

分析由 JNI 调用运行的 Java