최종 수정일 : 2019-03-29

JNI 기본 원리 이해 - 예제 프로그램

  • 예제 프로그램 : C 함수를 호출하는 간단한 자바 프로그램
  • 예제 프로그램 개발 순서 (JNI를 이용해서 개발할 때는 대부분 예제 프로그램과 동일한 절차를 밟는다.)
    (1) 자바 코드 작성
    (2) 자바 코드 컴파일
    (3) C 헤더 파일 생성
    (4) C 코드 작성
    (5) C 공유 라이브러리 생성
    (6) 자바 프로그램 실행

(1) 자바 코드 작성

  • C함수를 호출할 수 있는 자바 코드 HelloJNI.java 작성
  • 네이티브 메서드 : 자바 메서드, 실제로 자바가 아닌 C/C++ 같은 네이티브 언어로 작성된 함수
    (약속)
  • JNI 구현에서 메서드 선언은 자바 코드에서, 선언된 메서드의 실제 구현은 C/C++ 코드에서 이루어진다.
    이 책에서는 자바에서 선언된 메서드를 네이티브 메서드, C/C++ 코드로 구현된 함수를 JNI 네이티브 함수라고 부른다.

(2) 자바 코드 컴파일

자바 코드

(3) C/C++ 헤더 파일 생성

  • 자바 가상 머신은 자바 클래스 내부에 선언된 네이티브 메서드와 매핑할 C 함수를 로드된 라이브러리에서 찾아 매핑 테이블 형태로 만들어 놓는다. 그러고 나면 자바 네이티브 메서드와 C 함수가 링크된다.
  • 자바 가상 머신은 일반적인 형식의 C 함수를 자바 네이티브 메서드와 직접 매핑하지 않는다.

  • 자바 가상 머신은 네이티브 라이브러리를 로딩하면서 해당 라이브러리에 들어 있는 C 함수 가운데 어떤 함수가 자바 코드의 네이티브 메서드와 매핑될지 어떻게 식별할 수 있을까?
    • 함수 형태로 식별한다.
    • JNI 명세에서 정한 대로 함수 원형을 작성하면 자바 가상 머신은 해당 함수가 네이티브 메서드와 매핑될 함수라고 식별하게 한다.
    • JNI 명세에 나온 대로 함수 원형을 만드는 작업을 도와주는 것이 javah라는 툴이다. 이 툴은 \bin에 포함돼 있다. 자바 네이티브 메서드와 연결될 수 있는 C 함수의 원형을 생성해준다.
      • 사용법은 아래와 같다.
      • javah <native로 선언된 메서드를 포함한 자바 클래스 이름>
      • javah를 통해 출력되는 결과물은 입력 인자로 넘긴 자바 클래스 이름과 동일한 C언어 헤더 파일이다. 이 파일에는 javah의 입력 인자로 넘긴 자바 클래스의 네이티브 메서드와 JNI와 연결할 수 있는 C 함수의 원형이 정의돼 있다.
      • HelloJNI.h 파일에는 HelloJNI 클래스의 네이티브 메서드에 대한 C 함수의 원형이 들어간다.

자바 코드

자바 코드

  • javah에 의해 생성된 헤더 파일의 함수 이름
JNIEXPORT void JNICALL Java_HelloJNI_printHello(JNIEnv *, jobejct)
반환타입        접두사     클래스이름 네이티브 메서드 이름 공통 매개변수  
  • JNI 네이티브 함수가 어떤 자바 클래스의 어떤 네이티브 메서드와 매핑되어 있는지 알 수 있다.
  • 위의 예는 HelloJNI 클래스의 printHello() 네이티브 메서드와 연결되는 함수 원형이다.

  • javah가 생성하는 함수 원형의 매개변수
    • 첫 번째 두번째 매개변수로 JNIEnv *jobject라는 디폴트 매개변수가 포함되어 있다.
    • JNI를 지원하는 함수는 이 두개의 공통 매개변수를 반드시 포함해야 한다.
    • 첫 번째 매개 변수 JNIEnv * : JNI 인터페이스 포인터, 이 포인터를 통해 JNI 명세에 포함된 다양한 JNI 함수를 호출할 수 있다.
      (JNI 함수 : JNI 네이티브 함수가 아님. JNI 네이티브 함수에서 자바의 객체를 생성하거나 메서드를 호출하는 등의 일을 할 수 있게 JNI에서 기본적으로 제공하는 함수 모음)
    • 두 번째 매개 변수 타입 jobject : JNI에서 제공되는 자바 네이티브 타입, C 코드에서 자바 객체에 접근할 때 쓰인다. 이 매개변수에는 네이티브 메서드를 호출한 객체의 레퍼런스 값이 전달된다. 예에서 myJNI 객체의 레퍼런스 값이 전달된다.
    • 세 번째 매개 변수부터는 네이티브 메서드가 가지는 매개변수 타입과 비슷한 형태로 C 함수의 매개 변수가 각각 생성된다.
    • printString(String str)에는 String 타입 매개변수가 있으므로 C 함수에 jstring 타입의 매개변수가 하나 더 추가된다.
  • (참고) 자바 네이티브 타입
    • 자바는 플랫폼 독립적이므로 자바의 데이터 타입은 어떤 플랫폼에서든 메모리 크기가 동일하다.
    • 예를 들어 자바 int 타입은 모든 플랫폼에서 크기가 4바이트이다.
    • 하지만 C/C++ 같은 네이티브 언어에서는 동일한 데이터 타입이더라도 플랫폼에 따라 크기가 달라질 수 있다.
    • JNI 프로그래밍에서 자바 프로그램과 C/C++ 함수 사이의 데이터 교환이 자주 일어난다. 이때 두언어 사이에서 데이터 타입이 서로 통일되지 않는다면 프로그램의 정상 동작 여부를 보장할 수 없다.
    • JNI는 C/C++ 같은 네이티브 언어에서도 자바의 데이터 타입을 사용할 수 있게끔 자바 네이티브 타입을 제공한다.
    • JNI 프로그래밍을 하는 C/C++ 개발자들은 자바 코드에서 데이터(인자, 함수 반환 값)를 보내거나 받을 때 자바 네이티브 타입을 사용하면 된다.
      jni.h 와 jni_md.h 파일에 자바 네이티브 타입이 정의돼 있다.
    • 자바의 클래스, 객체 등과 같은 레퍼런스 타입에 대해서도 자바 네이티브 타입이 제공된다.
    • jni 명세 http://java.sun.com/docs/books/jni/

(4) C/C++ 코드 구현

자바 코드

(5) C 공유 라이브러리 생성

3단계 4단계에서 작성한 헤더 파일과 소스 파일을 가지고 공유 라이브러리를 만든다.
microsoft visual studio 를 이용해 코드를 빌드하고 라이브러리를 만들어 보자.

(6) 자바 프로그램 실행

예제 결과