获取 Java VM 参考,从 C++ 和并发创建 Java Object
Fetch Java VM Reference, create Java Object from C++ and Concurrency
我遇到以下情况:C++ 服务器应用程序正在侦听传入的客户端连接。在每次客户端连接尝试时,都会生成一个新的 session。此 session 将调用特定服务,具体取决于服务 ID,服务 ID 在来自客户端的序列化数据中提供。一旦结果从服务到达,session 就会将数据发送到客户端。
场景中的陷阱是,服务是在 Java 中实现的。
因此我的问题是:
- 如果有新的客户端请求到达,我如何使用来自 C++ 的 VM 引用实例化和调用 Java 服务 class?
我知道为此我需要一个 Java 虚拟机。因为 C++ 服务器 class 将首先从 Java 应用程序调用(通过 SWIG 生成的包装器)我想我可能会将此应用程序的 VM 引用传递给我的服务器 class (以及之后的 sessions)。
但是:
- 如何在我的 Java 代码中获取对当前 VM 的引用?
通常 Java 应用程序在启动服务器后什么都不做。也许我必须让它保持空闲状态以保持 VM 引用处于活动状态?关于在 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 but I have to admit that the solution is hard to understand and it remains unclear what the questioner was trying to achieve. In this post the author was doing something similar with Java build in types, but it seems that the code generator can not be used for own java types. I also knew that a new VM can be generated 可以完成这项工作,但如果可能的话,我想使用现有的。
编辑
to 1) 我不确定,但当我使用 C++ 服务器 class 加载库时,也许可以使用 jint JNI_OnLoad(JavaVM *vm, void *reserved);
方法获取指向 VM 的指针。不幸的是 Oracle documentation 没有解释这个问题。有人可能有这方面的经验吗?
The Invocation API + JNI Functions 会有帮助。
How can I obtain a reference to the current VM in my Java code?
- 调用
JNI_GetCreatedJavaVMs
获取 JavaVM*
参考。如果 JVM 已在当前进程中启动,则此函数通常 returns 正好是一个 JVM 引用的数组。
- 如果当前线程不是从 Java 创建的,请使用在步骤 1 中获得的引用调用
JavaVM->AttachCurrentThread
。如果当前线程已经与 JVM 相关联,请跳过此步骤。
- 调用
JavaVM->GetEnv
获取当前线程的 JNIEnv*
指针。使用 JNIEnv
结构,您将能够调用 JNI 函数,见下文。
How can I instantiate and call the Java service class using the VM reference from C++
- 使用
JNIEnv->FindClass
获取要实例化的 Java class 的 jclass
引用。
- 调用
JNIEnv->GetMethodID
以获得对 class' 构造函数的引用。默认构造函数(不带参数的构造函数)具有 "()V"
签名。
- 调用
JNIEnv->NewObject
从步骤 1 和 2 传递 jclass
和 jmethodID
以实例化给定的 class.
- 运行
JNIEnv->CallObjectMethod
to execute a Java method. obj
argument is an object reference obtained at step 3, and methodID
argument is a method you want to call obtained by 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*
、jclass
、jmethodID
。
JNIEnv*
与线程关联。它只能在一个线程内重复使用。
- JNI 函数本身是线程安全的。但是,如果您在 C++ 中使用静态变量,请确保在 C++ 领域中正确同步对这些变量的访问。
我遇到以下情况:C++ 服务器应用程序正在侦听传入的客户端连接。在每次客户端连接尝试时,都会生成一个新的 session。此 session 将调用特定服务,具体取决于服务 ID,服务 ID 在来自客户端的序列化数据中提供。一旦结果从服务到达,session 就会将数据发送到客户端。
场景中的陷阱是,服务是在 Java 中实现的。
因此我的问题是:
- 如果有新的客户端请求到达,我如何使用来自 C++ 的 VM 引用实例化和调用 Java 服务 class?
我知道为此我需要一个 Java 虚拟机。因为 C++ 服务器 class 将首先从 Java 应用程序调用(通过 SWIG 生成的包装器)我想我可能会将此应用程序的 VM 引用传递给我的服务器 class (以及之后的 sessions)。
但是:
- 如何在我的 Java 代码中获取对当前 VM 的引用?
通常 Java 应用程序在启动服务器后什么都不做。也许我必须让它保持空闲状态以保持 VM 引用处于活动状态?关于在 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 but I have to admit that the solution is hard to understand and it remains unclear what the questioner was trying to achieve. In this post the author was doing something similar with Java build in types, but it seems that the code generator can not be used for own java types. I also knew that a new VM can be generated 可以完成这项工作,但如果可能的话,我想使用现有的。
编辑
to 1) 我不确定,但当我使用 C++ 服务器 class 加载库时,也许可以使用 jint JNI_OnLoad(JavaVM *vm, void *reserved);
方法获取指向 VM 的指针。不幸的是 Oracle documentation 没有解释这个问题。有人可能有这方面的经验吗?
The Invocation API + JNI Functions 会有帮助。
How can I obtain a reference to the current VM in my Java code?
- 调用
JNI_GetCreatedJavaVMs
获取JavaVM*
参考。如果 JVM 已在当前进程中启动,则此函数通常 returns 正好是一个 JVM 引用的数组。 - 如果当前线程不是从 Java 创建的,请使用在步骤 1 中获得的引用调用
JavaVM->AttachCurrentThread
。如果当前线程已经与 JVM 相关联,请跳过此步骤。 - 调用
JavaVM->GetEnv
获取当前线程的JNIEnv*
指针。使用JNIEnv
结构,您将能够调用 JNI 函数,见下文。
How can I instantiate and call the Java service class using the VM reference from C++
- 使用
JNIEnv->FindClass
获取要实例化的 Java class 的jclass
引用。 - 调用
JNIEnv->GetMethodID
以获得对 class' 构造函数的引用。默认构造函数(不带参数的构造函数)具有"()V"
签名。 - 调用
JNIEnv->NewObject
从步骤 1 和 2 传递jclass
和jmethodID
以实例化给定的 class. - 运行
JNIEnv->CallObjectMethod
to execute a Java method.obj
argument is an object reference obtained at step 3, andmethodID
argument is a method you want to call obtained byGetMethodID
.
示例代码
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*
、jclass
、jmethodID
。 JNIEnv*
与线程关联。它只能在一个线程内重复使用。- JNI 函数本身是线程安全的。但是,如果您在 C++ 中使用静态变量,请确保在 C++ 领域中正确同步对这些变量的访问。