如何在C++(JNI)中设置正在运行的JVM的classpath?

4
在 C++(JNI)中,我使用以下JNI函数获取已经运行的JVM:
JNI_GetCreatedJavaVMs(&jvm,1,&vmnb);

然后我使用以下代码附加当前线程:

jvm->AttachCurrentThread((void**)&env, NULL);

问题:在这种情况下,我该如何设置classpath?谢谢。

注意:对于我来说,创建一个新的JVM并将classpath传递给新的JVM不是一个选项。


类路径是一个系统属性,用于在启动期间配置应用程序类加载器。更改系统属性很容易,但对于已经完成初始化的JVM,它对类加载没有实际影响。通常,支持更改应用程序类加载器(例如通过JVMTI)的JVM仅允许将新条目附加到末尾。 - Holger
事实上,将新条目附加到当前类路径就足够了。我已经通过Java实现了这一点(如我的答案中所提到的)。 - waheed
2个回答

4
由于Java可以在程序内部添加classpath,所以我找到了一种通过Java在C++中设置classpath的替代方法。由于我已经在运行JVM,因此我使用了在这个答案中介绍的附加classpath的方法(void addPath(String path)),并将其放置在已经在JVM中运行的Java程序中。然后,我通过JNI调用从C++访问Java程序中的addPath方法来增加classpath。从C++传递给addPath方法的classpath不应包括"-Djava.class.path",它应该只是.jar文件的完整路径,例如"C:\\folder\\abc.jar"。因此,步骤如下:1)获取已经运行的JVM,将当前线程附加到该JVM上,获取JNI环境指针,然后使用JNI从C++中调用另一个运行线程中的addPath java函数。现在,我可以成功地从C++中访问新的classpath(.jar文件)所在的类。

1
我遇到了这个问题,而且我没有选择回调到JVM中,所以我在JNI端实现了整个“add_path”业务。
void add_path(JNIEnv* env, const std::string& path)
{
    const std::string urlPath = "file:/" + path;
    jclass classLoaderCls = env->FindClass("java/lang/ClassLoader");
    jmethodID getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
    jobject classLoaderInstance = env->CallStaticObjectMethod(classLoaderCls, getSystemClassLoaderMethod);
    jclass urlClassLoaderCls = env->FindClass("java/net/URLClassLoader");
    jmethodID addUrlMethod = env->GetMethodID(urlClassLoaderCls, "addURL", "(Ljava/net/URL;)V");
    jclass urlCls = env->FindClass("java/net/URL");
    jmethodID urlConstructor = env->GetMethodID(urlCls, "<init>", "(Ljava/lang/String;)V");
    jobject urlInstance = env->NewObject(urlCls, urlConstructor, env->NewStringUTF(urlPath.c_str()));
    env->CallVoidMethod(classLoaderInstance, addUrlMethod, urlInstance);
    std::cout << "Added " << urlPath << " to the classpath." << std::endl;
}

这只是证明了Java将JavaVM设置为每个进程的单例是一个糟糕的决定。他们至少应该让一个进程的多个用户能够使用不同的类路径。 - user13947194

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接