如何用jni配置spring?

How to configure spring with jni?

我需要将 spring 与一些用 C 编写的本机代码集成,我是 spring 的新手,如果有人有集成经验,我对此一无所知 spring 与 JNI 然后请与我分享。

提前致谢。

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

  1. 忘记与 "Spring" 集成。专注于与 Java 整合,让 Spring 稍后帮助您。
  2. 非常非常小心 C 中的类型和内存分配
  3. Here 是一本关于 JNI 的书,我在研究它时发现它非常有用。它有点过时但仍然有效
  4. 我用 C 完成了大部分工作,然后在一个简单的单一方法挂钩中修补到 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 注释

希望对您有所帮助

与之前的回答相呼应 Spring 集成在这里并不是真正重要的事情。更重要的是,拥有与本地 C/C++ 节点的 JVM 接口。由于提出了这个问题,因此有许多可用的在线资源可以帮助新用户解决这个问题 space。

JNI Integration walktrough Java™ Native Interface: Programmer's Guide and Specification 一书也很有用 如果你真的想深入,那么 official specification 非常有帮助