본문 바로가기

Programming/Java

JNI 를 이용한 Java Interface MiddleWare 사용하기

소개

JNI( Java Native Interface) 는 프로그래밍 인터페이스 이다. JNI 는 JVM 내부에서 실행되는 Java 코드를

C, C++ 등과 같은 걸로 구성된 라이브러리 등을 내부적으로 운영할 수 있도록 한다.

JNI 의 사용유형은 다음처럼 두가지 경우이다.

  • Java→ C/C++
    • 가장일반적인 형태로 android 가 대표적
    • OS 의 native 한 부분을 java 로 구현하기 어렵거나 성능적 이슈가 있는 경우 사용된다.
    • 기존의 legacy 시스템
    • 특수 하드웨어 제어
  • C/C++ → Java
    • Lucene 엔진이 대표적( 기존 Java 엔진의 유용성이 매우 큰 경우 )
    • 기능, 성능면에서 이점은 없으나 기존 시스템이 Java 로 구현이 완전하게 되어 있는 경우
    • 새로 구축하는 비용이 부담되는 경우 사용됨

JNI 를 통해 Java Interface 만 제공하는 MiddleWare 로의 접근에 대한 가능성 조사이며 JDBC 를 사용한다는 전제로

C/C++→ Java 경우에 대해서만 언급한다.

장점

  • C/C++ 인터페이스를 제공하지 않는 경우에도 우회적으로 사용이 가능하다.
  • 최신 트랜드에 따르는 Software 의 대부분은 Java 를 우선지원하거나 Java로 만들어져 있다.

단점

  • JDBC 에 준하는 C/C++ 인터페이스를 설계해야 한다.
  • ODBC 대비 throughput 및 latency 저하가 예상된다.
  • 관리포인트 증가
    • JVM 을 실행한 상태에서 JNI 를 이용한 메모리 관리
    • GC( garbage collection ) 관리를 통한 성능 관리
    • 기존 Java 사용하던 환경과 다른 관리 기준

example

JNI 를 이용한 간단한 테스트 example

Java Code

public class JniTest{
    public static void main(String[] args){
        System.out.println("Hello World " + args[0] );
    }

}

C Code

#include <jni.h>


#define PATH_SEPARATOR ';'
#define USER_CLASSPATH "."



void main(){
    JNIEnv *env;
    JavaVM *jvm;
    jint res;
    jclass cls;
    jmethodID mid;
    jstring jstr;
    jclass stringClass;
    jobjectArray args;

    JavaVMInitArgs vm_args;
    JavaVMOption options[1];
    options[0].optionString = "-Djava.class.path=" USER_CLASSPATH;
    vm_args.version = 0x00010002;
    vm_args.options = options;
    vm_args.nOptions = 1; 
    vm_args.ignoreUnrecognized = JNI_TRUE;

    res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    if (res < 0) {
        fprintf(stderr, "Can't create Java VM\n");
        exit(1);
    }  

    cls= (*env)->FindClass(env, "JniTest");
    if (cls == 0) {
        fprintf(stderr, "Can't find JniTest class\n");
        exit(1);
    }  

    mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
    jstr = (*env)->NewStringUTF(env, "arg1");
    stringClass = (*env)->FindClass(env, "java/lang/String");
    args = (*env)->NewObjectArray(env, 1, stringClass, jstr);
    (*env)->CallStaticVoidMethod(env, cls, mid, args);

    if((*env)->ExceptionOccurred(env)){
        (*env)->ExceptionDescribe(env);
    }  

    (*jvm)->DestroyJavaVM(jvm);
}

컴파일 및 실행

# jni.h 헤더파일을 위해





export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64

# $JAVA_HOME/include
# $JAVA_HOME/include/linux 가 필요하다.

INC=-I$JAVA_HOME/include
INC2=-I$JAVA_HOME/include/linux

# JNI 라이브러리

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64/lib/amd64/server
LIB=/usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64/lib/amd64/server/libjvm.so

gcc $INC $INC2 JniTest.c $LIB

$ a.out
Hello World arg1
chlee@dev:~/workspace/jni
$