Hướng dẫn lập trình JNI (Java Native Interface)

From CodeForLife
Revision as of 17:32, 11 December 2017 by Thangdb (talk | contribs) (Created page with " __TOC__ == '''Giới thiệu tổng quan''' == '''JNI '''('''Java Native Interface''') là giao diện lập trình cho phép sử dụng các ngôn ngữ khác (C/C++, Ass...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Giới thiệu tổng quan

JNI (Java Native Interface) là giao diện lập trình cho phép sử dụng các ngôn ngữ khác (C/C++, Assembly) trong Java. JNI thường sử dụng xây dựng các hàm core, giúp tăng hiệu năng hệ thống.

Mô hình đơn giản bạn xem ảnh dưới:
Jni model.png

Mô hình chi tiết các tầng:
Jni model-01.png

Lý do sử dụng JNI:

  • Vấn đề hiệu năng: Thông thường những tác vụ cần hiệu năng cao thường được xử lý C/C++, còn Java chỉ gọi lại mà thôi.
  • Truy cập APIs mức OS
  • Chuyển ứng dụng hoặc dịch vụ từ C/C++ sang Java: Trường hợp này bạn sử dụng JNI sẽ nhanh hơn rất nhiều so với việc code lại toàn bộ ứng dụng bằng Java.

Chuẩn bị môi trường

Để build và chạy ứng dụng, bạn cần cài đặt tối thiểu hai công cụ sau:

  • JDK: Từ JDK 2  trở lên, nhưng thường sử dụng từ JDK 6. Hiện tại đã có JDK 8.
  • C/C++ Compiler: Trình biên dịch C/C++. Tùy trên OS nào mà bạn chọn cho phù hợp.

Ngoài ra, bạn cài đặt thêm IDE nào đó giúp cho việc lập trình đơn giản hơn, chẳng hạn: Netbeans hoặc Eclipse.

Việc cài đặt các công cụ này khác nhau đôi chút, phụ thuộc vào hệ điều hành. Ở đây tôi xin hướng dẫn bạn build và chạy trên 02 hệ điều hành:

  • Hệ điều hành Windows
  • Hệ điều hành Ubuntu

Chuẩn bị môi trường trên Ubuntu

Hiện tại sử dụng  hệ điều hành Ubuntu 16.04, với các phiên bản Ubuntu khác việc cài đặt cũng tương tự, đôi khi khác một chút.

Chuẩn bị môi trường trên Windows

 

Từng bước tạo ví dụ đơn giản với JNI

Để viết một ứng dụng JNI, ta phải thực hiện từng bước như sau:

Jni step by step.png

STT Bước thực hiện Mô tả chi tiết
1 Viết mã Java - Trước tiên bạn cần thiết kế hàm, các tham số trước để java có thể gọi xuống C/C++. 
- Tạo lớp chứa các hàm cần gọi, các hàm này yêu cầu bắt buộc phải có từ khóa native. Hàm này bạn có thể để private/protected/public, có thể để static hoặc không tùy bạn.
- Thêm đoạn code load thư viện System.loadLibrary khi lớp này sử dụng.
- Bạn có thể đặt hàm native cùng tên nhưng khác tham số, nhưng khuyên cáo dung tên hàm native khác nhau để tránh nhầm lẫn trong C/C++.
2 Biên dịch thành tệp class Sử dụng công cụ javac của jdk để build thành tệp .class. Nếu bạn dùng IDE (Netbean, Eclipse,…) thì tương đương việc bạn build ứng dụng.
3 Sinh tệp .h - Sử dụng công cụ javah của JDK để tạo từ tệp java. Nhìn vào tệp .h sinh ra bạn sẽ hiểu được cú phấn ánh xạ tên hàm giữa Java và C++.
- Bạn để ý thấy tất cả các hàm trên JNI đều phải có hai tham sốJNIEnv* và jclass/jobject, sau đó mới là các tham số của hàm tương ứng trên Java, trong đó: jclass sử dụng cho các hàm static, jobject sử dụng cho các hàm không phải static
- Bạn cũng cần chú ý đối với các hàm native cùng tên nhưng khác tham số.
4 Viết code trên C/C++ Cài đặt các hàm native trên C/C++
5 Dịch native code Sử dụng gcc để dịch native code thành thư viện .so trên Ubuntu/Linux, .dll trên Windows.
6 Chạy ứng dụng Sử dụng java để chạy ứng dụng

<Xem ví dụ JNI Demo>

Cơ bản về JNI

JNIEnv và JavaVM

Trong các hàm Native luôn luôn có hai tham số:

  • JNIEnv: Đây là con trỏ trỏ tới cấu trúc JNINativeInterface, nơi lưu trữ tất cả các con trỏ hàm Native, và cung cấp nhiều hàm tiện ích giúp tương tác với JVM và làm việc với đối tượng Java. Chi tiết xem: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
  • jclass/jobject: Con trỏ tham chiếu tới cấu trúc chứa thông tin lớp và đối tượng trên Java.

JNI cho phép bạn chồng hai hàm JNI_OnLoad và JNI_OnUnload để xác định khi nào thư viện Native được load và qua hàm này bạn lưu lại đối tượngJavaVM* để sử dụng:

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved);
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved);

Việc lưu lại đối tượng JavaVM sẽ giúp bạn có thể chủ động gọi hàm callback lên Java.Chi tiết sẽ trình bày ở phần dưới.