JNI 加载类最佳实践

问题描述 投票:0回答:1

我目前正在开发一个混合 java/C 项目。 因为我喜欢尽可能减少运行时障碍,所以我倾向于将资源(图片)集成到我的二进制文件中,从而消除诸如“找不到图片”之类的错误,这些错误可能在用户移动我的二进制文件时发生。 我知道我可以将 java 文件包含到我的 C 可执行文件中(例如通过 C23 #embed 或 xxd)。通常,在现代机器上,数 MB 的二进制文件不再是问题。 然后我可以通过(程序开头的一个简单的 foreach 循环)加载我的 C 程序中的类:

jclass DefineClass(JNIEnv *env, const char *name, jobject loader,
const jbyte *buf, jsize bufLen);

我的问题是:如何对整个 jar 文件执行此操作?我想包括,例如我的二进制文件中的selenium API?是否足以解压缩每个 jar 文件,将其包含在二进制文件中,并定义它们? 有什么我可能遗漏的障碍吗?

编辑:我的切入点在 C 端。事实上,整个应用程序不包含任何 Java 代码,它只是通过 JNI 使用 Selenium 的一些 API。

java c jar java-native-interface
1个回答
0
投票

作为一种完全不同的方法,为什么不滥用 JAR 底层的 ZIP 文件格式呢? ZIP 文件将其元数据存储在文件末尾,这意味着您可以简单地将 JAR 文件附加到二进制文件并将其添加到自己的类路径中。

举个简单的例子,以 Main.java 为例:

class Main {
    public static void main(String[] args) {
        System.out.println("Hello from java");
    }
}

和jni.cpp:

#include <jni.h>
#include <string>

int main(int argc, char **argv) {
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
        std::string option = "-Djava.class.path=";
        option += argv[0];
    options[0].optionString = const_cast<char *>(option.c_str());
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */
    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    delete[] options;
    /* invoke the Main.test method using the JNI */
    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(cls, mid);
    /* We are done. */
    jvm->DestroyJavaVM();
}

然后你可以这样做:

$ make jni
$ javac Main.java
$ jar cf code.jar Main.java
$ cat jni code.jar > jni-combined
$ ./jni-combined
Hello from java
© www.soinside.com 2019 - 2024. All rights reserved.