java - 如何使用jni配置spring?

标签 java eclipse spring java-native-interface

我需要将 spring 与一些用 C 编写的 native 代码集成,我是 spring 的新手,对此没有任何想法,如果有人有将 spring 与 JNI 集成的经验,请与我分享。

提前致谢。

最佳答案

这个问题相当模糊,但我可以根据我过去所做的工作提供一些建议。

  1. 忘记与“Spring”集成。集中精力与 Java 集成,稍后让 Spring 帮助您。
  2. 对 C 语言中的类型和内存分配要非常非常小心
  3. Here是一本关于 JNI 的书,我在研究它时发现它非常有帮助。虽然有点过时,但仍然有效
  4. 我用 C 语言完成了大部分工作,然后将一个简单的单一方法 Hook 修补到了 Java 中。这样,我就用其母语完成了与现有代码的大部分集成。
  5. 为您的 C 代码提供一个 main 方法,让您可以独立于 Java 来测试 C 代码。然后,您可以将 C 文件编译为库 (dll/so) 和可执行文件。可执行文件可以使用参数单独调用,以测试对现有调用的调用。

大致流程是。

Java结束

public class statusBlock {
    /* A Java representation of a Status Block */
    private long errcode = 0;
    private long errref = 0;
    private String errmsg = "";
    private long[] TmidArray;
    private long evt_id = 0;
    private short IgViolation_severity = 0;
}

public class MyFunkyJNIClass {
    private Object response;

    /**
     * To generate the C-header for a native call use: javah -jni
     * example.package.MyFunkyJNIClass from target/classes folder.
     */
    private native int nativeExecuteFunction(int callType, Object payload, Object response);

    public MyFunkyJNIClass() {
        System.loadLibrary("theCLibrary");
    }
}

在上面的示例中,我使用 System.loadLibrary 加载代码的 C 端,并定义了一些可以从 C 代码填充的字段。要执行,只需调用 native 函数 nativeExecuteFunction(1, "my Payload", respObject); 在 C 端,我可以使用第一个参数来选择要执行的操作。 它简化了我当时的问题

C面

JNIEXPORT jint JNICALL Java_example_package_MyFunkyJNIClass_nativeExecuteFunction(JNIEnv *env, jobject this, jint CallType, jobject Payload)
{
    // **** JNI Specific declarations for mapping ****
    jclass          cls, cls2, cls3;
    jmethodID       mid, mid2;
    jfieldID        fid;
    jint            rc = 0;
    jsize           js = 0;
    jbyte           jb;
    jobject         jobj, jobj2, jro;
    jobjectArray    jobjArray, jobjArray2;

    _svc_results    results;

    switch ((int)CallType)
    {
    case CALLTYPE1:       // 1
        DEBUG_PRINT("JNI Call Type 1 in progress...\n");
        // JNI mapping happens here
        stat = DoSomethingInC(args, &results);

        // Map from C structure (_statblk) to Java object
        if (stat == SUCCESS) {
            DEBUG_PRINT("\tMapping from C structure (_statblk) to Java object\n");

            cls  = (*env)->FindClass(env, "Lexample/package/statusBlock;");
            mid  = (*env)->GetMethodID(env, cls, "<init>", "()V"); if (mid == NULL) return -1;
            jro  = (*env)->NewObject(env, cls, mid); if (jro == NULL) return -1;

            fid  = (*env)->GetFieldID(env, cls, "errcode","I"); if (fid == NULL) return -1;
            (*env)->SetIntField(env, jro, fid, (jint)results.statblk.errcode);
            DEBUG_PRINT("\t\tMapped errcode: %d\n",results.statblk.errcode);

            fid  = (*env)->GetFieldID(env, cls, "errref","I"); if (fid == NULL) return -1;
            (*env)->SetIntField(env, jro, fid, (jint)results.statblk.errref);
            DEBUG_PRINT("\t\tMapped errref: %d\n",results.statblk.errref);

            fid  = (*env)->GetFieldID(env, cls, "errmsg","[B"); if (fid == NULL) return -1;
            jobj = (*env)->NewByteArray(env, MAX_ERR);
            (*env)->SetByteArrayRegion(env, (jbyteArray)jobj, 0, MAX_ERR, (jbyte*)results.statblk.errmsg);
            (*env)->SetObjectField(env, jro, fid, jobj);
            (*env)->DeleteLocalRef(env, jobj);
            DEBUG_PRINT("\t\tMapped errmsg: %s\n",results.statblk.errmsg);

            fid  = (*env)->GetFieldID(env, cls, "TmidArray","[I"); if (fid == NULL) return -1;
            jobj = (*env)->NewIntArray(env, (jsize)results.statblk.TmidArray.TmidArray_len);
            (*env)->SetIntArrayRegion(env, (jintArray)jobj, 0, 
                                      (jsize)results.statblk.TmidArray.TmidArray_len,
                                      (jint*)results.statblk.TmidArray.TmidArray_val);
            (*env)->SetObjectField(env, jro, fid, jobj);
            (*env)->DeleteLocalRef(env, jobj);
            DEBUG_PRINT("\t\tMapped TmidArray\n");

            fid  = (*env)->GetFieldID(env, cls, "evt_id","I"); if (fid == NULL) return -1;
            (*env)->SetIntField(env, jro, fid, (jint)results.statblk.evt_id);
            DEBUG_PRINT("\t\tMapped evt_id: %d\n",results.statblk.evt_id);

            cls  = (*env)->GetObjectClass(env, this);
            fid  = (*env)->GetFieldID(env, cls, "response","Ljava/lang/Object;"); if (fid == NULL) return -1;
            (*env)->SetObjectField(env, this, fid, jro);

            DEBUG_PRINT("\tMapping from C structure (_statblk) to Java object - DONE\n");
        } else {
            DEBUG_PRINT("JNI Call Type 1 in progress... Returning Error: %d\n", stat);
            return (jint)stat;
        }

        /* Free our native memory */
        cls  = (*env)->GetObjectClass(env, Payload);
        fid  = (*env)->GetFieldID(env, cls, "message","Ljava/lang/String;"); if (fid == NULL) return -1;
        jobj = (*env)->GetObjectField(env, Payload, fid);
        GPS_Free(results.statblk.TmidArray.TmidArray_val);
        GPS_Free(results.statblk.ErrorArray.ErrorArray_val);
        DEBUG_PRINT("JNI RTP Posting in progress... DONE\n");
        break;
    case PING:          // 2
        DEBUG_PRINT("No Java to C mapping required\n");
        DEBUG_PRINT("JNI Ping in progress...\n");
        stat = doPing();

        DEBUG_PRINT("No C to Java mapping required\n");
        // Stop null pointer exception if client tries to access the response object.
        cls  = (*env)->FindClass(env, "Lexample/package/EmptySerializableClass;");
        mid  = (*env)->GetMethodID(env, cls, "<init>", "()V"); if (mid == NULL) return -1;
        jro  = (*env)->NewObject(env, cls, mid); if (jro == NULL) return -1;

        cls  = (*env)->GetObjectClass(env, this);
        fid  = (*env)->GetFieldID(env, cls, "response","Ljava/lang/Object;"); if (fid == NULL) return -1;
        (*env)->SetObjectField(env, this, fid, jro);
        DEBUG_PRINT("JNI Ping in progress... DONE\n");

        return (jint)rpc_stat;
        break;
    default:
        fprintf(stderr,"Unknown call type\n");
        rc = -1;
        break;
    }

    return rc;
}

我可以继续说下去,但这只是需要仔细阅读那本书。

实际上不需要与 Spring 进行任何进一步的集成。您可以在 MyFunkyJNIClass 上粘贴 @Component@Service 注释。

希望这对您有帮助。

关于java - 如何使用jni配置spring?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36665212/

相关文章:

java - Spring - 根据 bean 验证 Controller 内的输入

java - Java 可以帮助我避免 equals() 中的样板代码吗?

android - 在 Android 中的 Activity 和 Intent 之间传递整数总是导致零/空

java - Mongodb 的查询选项有什么用?

java - 使用依赖于 Spring Security 的 JUnit 测试 Spring Controller

eclipse - 工作区 eclipse 中已存在具有该名称的项目

java - 不幸的是,应用程序已停止工作?

spring - 使用 Spring WebFlux 客户端使用 REST 端点时出错

java - 如何阻止 Spring 重定向 url 被编码

spring - 尝试运行 npm run build 时出错