gpt4 book ai didi

java - 获取 Java VM 引用,从 C++ 和并发创建 Java 对象

转载 作者:太空狗 更新时间:2023-10-29 20:55:30 25 4
gpt4 key购买 nike

我遇到以下情况:C++ 服务器应用程序正在监听传入的客户端连接。在每次客户端连接尝试时,都会生成一个新 session 。此 session 将调用特定服务,具体取决于服务 ID,服务 ID 在来自客户端的序列化数据中提供。一旦结果从服务到达, session 就会将数据发送到客户端。

场景中的陷阱是,该服务是用 Java 实现的。

因此我的问题是:

  1. 如果有新的客户端请求到达,我如何使用来自 C++ 的 VM 引用实例化和调用 Java 服务类?

我知道为此我需要一个 Java 虚拟机。因为 C++ 服务器类将首先从 Java 应用程序调用(通过 SWIG 生成的包装器),我想我可能会将此应用程序的 VM 引用传递给我的服务器类(以及之后的 session )。

但是:

  1. 如何在我的 Java 代码中获取对当前 VM 的引用?

通常,Java 应用程序在启动服务器后什么都不做。也许我必须让它保持空闲状态以保持 VM 引用处于 Activity 状态?关于在 C++ 和 Java 交互中对服务的并发调用(除了服务内部的正常并发处理之外),有什么我应该特别担心的吗?

例子:

//Java Service
public class JMyService{
public String loadContactInformation(int userid){
return "test";
}
}

//C++ (very simplified)
class Session{
public:
//[...]
void handleWrite(){
vm = getVMReference(); //is saved beforehand
if(serviceId == CONTACT_INFO){
//todo call JMyService.loadContactInformation
}
}
}

我已经看到了 this question但我不得不承认解决方案很难理解,而且提问者试图达到的目的仍然不清楚。在 this post作者正在做一些类似于 Java 内置类型的事情,但似乎代码生成器不能用于自己的 java 类型。我也知道that a new VM can be generated完成这项工作,但如果可能的话,我想使用现有的。

编辑

to 1) 我不确定,但也许 jint JNI_OnLoad(JavaVM *vm, void *reserved); 方法可用于在我加载库时获取指向 VM 的指针与 C++ 服务器类。不幸的是 Oracle documentation不解释这个问题。有人可能有这方面的经验吗?

最佳答案

The Invocation API + JNI Functions会有帮助。

How can I obtain a reference to the current VM in my Java code?

  1. 调用JNI_GetCreatedJavaVMs获取 JavaVM* 引用。如果 JVM 已在当前进程中启动,此函数通常会返回一个恰好包含一个 JVM 引用的数组。
  2. 如果当前线程不是从 Java 创建的,调用 JavaVM->AttachCurrentThread使用在步骤 1 中获得的引用。如果当前线程已与 JVM 关联,​​请跳过此步骤。
  3. 调用JavaVM->GetEnv获取当前线程的 JNIEnv* 指针。使用 JNIEnv 结构,您将能够调用 JNI 函数,见下文。

How can I instantiate and call the Java service class using the VM reference from C++

  1. 使用JNIEnv->FindClass获取要实例化的 Java 类的 jclass 引用。
  2. 调用JNIEnv->GetMethodID获取对类构造函数的引用。默认构造函数(不带参数的构造函数)具有 "()V" 签名。
  3. 调用JNIEnv->NewObject从步骤 1 和 2 传递 jclassjmethodID 以实例化给定的类。
  4. 运行 JNIEnv->CallObjectMethod执行 Java 方法。 obj参数是第3步得到的对象引用,methodID参数是GetMethodID得到的你要调用的方法。 .

示例代码

    JavaVM* vm;
jsize vmCount;
if (JNI_GetCreatedJavaVMs(&vm, 1, &vmCount) != JNI_OK || vmCount == 0) {
fprintf(stderr, "Could not get active VM\n");
return NULL;
}

JNIEnv* env;
jint result = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (result == JNI_EDETACHED) {
result = vm->AttachCurrentThread((void**)&env, NULL);
}
if (result != JNI_OK) {
fprintf(stderr, "Failed to get JNIEnv\n");
return NULL;
}

jclass cls = env->FindClass("JMyService");
jmethodID ctor = env->GetMethodID(cls, "<init>", "()V");
jobject service = env->NewObject(cls, ctor);

jmethodID loadMethod = env->GetMethodID(cls, "loadContactInformation", "(I)Ljava/lang/String;");
jobject serviceResult = env->CallObjectMethod(service, loadMethod, userId);
return serviceResult;

注意事项

  • 您可以在整个应用程序中缓存和重用 JavaVM*jclassjmethodID
  • JNIEnv* 与线程关联。它只能在一个线程内重复使用。
  • JNI 函数本身是线程安全的。但是,如果您在 C++ 中使用静态变量,请确保在 C++ 环境中正确同步对这些变量的访问。

关于java - 获取 Java VM 引用,从 C++ 和并发创建 Java 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35583247/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com