Java

[JAVA] JAVA 네이티브 언어와 통신하기 위한 JNI 개념

코딩 코딩 코오딩 2024. 8. 11. 21:18

😀 이 개념을 왜 정리하게 되었는지?

최근 진행한 업무 중 특정 파일을 암호화 처리후 저장하는 기능 개발 작업을 하게 되었습니다.
이때, 외부에서 인증 받은 다른 기업의 라이브러리를 사용해 암호화를 해야했고 그 기관에서 제공하는 모듈을 활용하여 암호화 하는 작업이었습니다.

이때 그 기관에서 제공 받은 암호화 모듈을 C++ 로 개발된 모듈이었으며,
현재 회사에서 운영중인 서비스는 Java 로 개발이 되어있기 때문에 상호작용을 위해서는 JNI 로 개발된 모듈을 제공해주었습니다.

따라서 이때 JNI 개념을 한번 정리하는 시간이 필요하다 생각했습니다.

 


🙂 JNI 는 무엇일까

JVM의 관점에서 "Java™" 및 "native" 의 두 가지 유형의 코드가 있습니다. JNI (Java Native Interface) 는 둘 사이에 잘 정의되고 플랫폼 독립적인 인터페이스를 설정합니다.

원시 코드는 실행 중인 JVM에서 "원시 메소드" 로, "호출 API" 를 사용하여 JVM을 작성하는 코드로 Java와 함께 사용할 수 있습니다.

 

참고로 인터페이스라는 개념은 중간 경계에 있는 역할을 하며 통로의 역할을 하는 통상적인 개념이라 생각하면 됩니다.

"네이티브"라는 용어는 프로그래밍에서 특정 플랫폼이나 운영 체제에서 직접 실행되는 코드를 의미합니다. 즉, 네이티브 코드는 해당 플랫폼의 머신 코드로 컴파일되어 운영 체제와 직접 상호 작용할 수 있는 언어로 작성된 코드입니다.

JNI(Java Native Interface)는 자바와 다른 프로그래밍 언어(주로 C 또는 C++)로 작성된 코드 간의 상호 작용을 가능하게 하는 자바의 인터페이스입니다.

 

여기서 말하는 "원시 코드"는 JVM에서 실행되는 네이티브 코드를 의미합니다. 네이티브 코드란, Java로 작성된 코드가 아닌, 특정 운영체제와 하드웨어에서 직접 실행될 수 있는 코드입니다. "네이티브"는 C 언어 계열에 국한되지 않지만, 일반적으로 운영 체제에서 직접 실행되는 언어를 지칭합니다.

주로 C, C++ 등의 언어로 작성됩니다. 이러한 네이티브 코드는 성능이 중요한 작업이나, Java만으로는 수행하기 어려운 시스템 레벨의 작업을 수행할 때 사용됩니다.

JNI를 사용하면 자바 애플리케이션에서 네이티브 라이브러리를 호출하고, 네이티브 코드와 자바 객체 간의 데이터를 전송할 수 있습니다.

 

🙂 JNI 주요 특징

  1. 상호 운용성: JNI를 통해 자바 애플리케이션이 C/C++로 작성된 라이브러리와 상호 작용할 수 있습니다. 이로 인해 성능이 중요한 부분이나 기존의 C/C++ 라이브러리를 재사용할 수 있습니다.
  2. 성능: JNI를 사용하면 자바의 성능 한계를 극복할 수 있으며, CPU 집약적인 작업이나 하드웨어 접근이 필요한 경우 유용합니다.
  3. 플랫폼 의존성: JNI는 플랫폼에 따라 다르게 구현될 수 있으므로, 특정 운영 체제에 종속적인 코드를 작성할 수 있습니다.

 

JNI 사용 예시

JNI를 사용하려면 다음과 같은 단계가 필요합니다:

  • 단계 1: Java 코드 작성
    먼저, 네이티브 메소드를 선언하는 Java 클래스를 작성합니다.
public class HelloJNI {  

    // 네이티브 메소드 선언  
    public native String sayHello();  

    // 네이티브 라이브러리 로드  
    static {  
        System.loadLibrary("hello");  
    }  
    public static void main(String[] args) {  
        HelloJNI helloJNI = new HelloJNI();  
        String message = helloJNI.sayHello(); // 네이티브 메소드 호출  
        System.out.println(message); // 네이티브 메소드 결과 출력  
    }  
}
  • 단계 2: JNI 헤더 파일 생성
    Java 코드에서 네이티브 메소드를 선언한 후, javac를 사용하여 컴파일합니다.
javac -h . HelloJNI.java
/* DO NOT EDIT THIS FILE - it is machine generated */  
#include <jni.h>  
/* Header for class HelloJNI */  

#ifndef _Included_HelloJNI  
#define _Included_HelloJNI  
#ifdef __cplusplus  
extern "C" {  
#endif  
/*  
 * Class:     HelloJNI * Method:    sayHello * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello  
  (JNIEnv *, jobject);  

#ifdef __cplusplus  
}  
#endif  
#endif
  • 3 단계 : C 코드 작성
    생성된 헤더 파일을 기반으로 네이티브 메소드를 구현하는 C 코드를 작성합니다.
#include <jni.h>
#include "HelloJNI.h"
#include <stdio.h>

JNIEXPORT jstring JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
    return (*env)->NewStringUTF(env, "Hello from C!");
}
  • 4단계 : 네이티브 라이브러리 컴파일

운영체제에 따라 네이티브 라이브러리를 컴파일합니다.

gcc -shared -o libhello.dylib -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin HelloJNI.c
  • 단계 5: Java 프로그램 실행
    java -Djava.library.path=. HelloJNI
  • 결과
  • Hello from C!

이렇게 JNI 를 사용해 보았지만 개발을 진행하며 겪은 문제에 대하여 정리를 하고 마무리를 하려 한다.

 

 

진행 중 겪은 문제

  • 환경변수 설정 문제
    첫번째로 마주한 문제는 라이브러리에 대한 인식이었습니다.
    사용하는 IDE 에서 JNI 모듈이 있는 라이브러리를 인식하지 못하는 문제를 마주하게 되었습니다.
    이때 해결 법으로는 IDE 의 RunTime 또는 Debug 시점에 환경 변수를 경로에 설정하면됩니다.
    그러면 문제가 해결되고 잘 실행할 수 있었습니다.

참고

https://velog.io/@jewan/CS-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EC%BD%94%EB%93%9CNative-Code

https://www.ibm.com/docs/ko/sdk-java-technology/8?topic=jni-overview

https://blog.naver.com/bumsukoh/110127599898

반응형