Нативна бібліотека
Це бібліотека, написана на мові програмування, яка компілюється безпосередньо в машинний код, специфічний для певної архітектури або операційної системи. Нативні бібліотеки використовуються програмами, що написані на тій же мові програмування або через механізми міжмовної взаємодії, такі як JNA/JNI в Java. Нативні бібліотеки можуть бути як статичними, так і динамічними.
Статична бібліотека
Набір функцій, які включаються безпосередньо в бінарний файл програми на етапі компіляції. Вони стають нероздільною частиною програми.
Динамічна бібліотека
Не включається в бінарний файл програми на етапі компіляції. Замість цього, програми завантажують динамічні бібліотеки в пам'ять під час виконання, коли це необхідно. Декілька програм можуть використовувати одну й ту ж динамічну бібліотеку, що допомагає економити пам'ять.
Динамічні бібліотеки зазвичай мають розширення .dll на Windows, .so на Linux і .dylib на macOS.
І логічно, що завантаження бібліотеки вимагає щоб вона була присутньою на системі під час виконання.
JNA
або Java Native Access — це один з інструментів Java, який дозволяє розробникам забезпечити безпосередній доступ до native-функцій та бібліотек, написаних на C, C++ та інших мовах. Це корисно, коли вам потрібно використовувати функції, які не доступні в стандартній бібліотеці Java, або коли вам потрібно покращити продуктивність за допомогою нативного коду.
Основна концепція полягає в тому, щоб створити Java інтерфейс, що відповідає нативній бібліотеці, і використовувати цей інтерфейс для виклику native-функцій. JNA контролює всі нюанси прив'язки, включаючи перетворення типів даних і виклик функцій.
Що це нам дає?
1. Доступ до native API: Часто Java може не мати доступу до специфічних функцій операційної системи або апаратного забезпечення. JNA дозволяє викликати ці функції напряму.
2. Продуктивність: Деякі операції можуть бути виконані швидше в native-коді, ніж в Java. JNA дозволяє вам використовувати ці оптимізації.
Створення JNA-інтерфейсу
Спершу ви маєте визначити Java інтерфейс, що відображає native-бібліотеку. Цей інтерфейс має включати сигнатури всіх функцій, які ви хочете викликати. Потім ви викликаєте ці функції через JNA, який конвертує Java типи даних у відповідні нативні типи.
Припустимо, ми хочемо викликати getpid (отримати ID потоку) і getenv, який повертає значення змінної оточення. Спочатку, нам потрібно додати залежність JNA до нашого проекту.
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.13.0</version>
</dependency>
Тепер створимо JNA інтерфейс для бібліотеки libc *, яка містить getpid і getenv:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public interface CLibrary extends Library {
CLibrary INSTANCE = Native.load((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
int getpid();
String getenv(String name);
}
Main:
public class Main {
public static void main(String[] args) {
CLibrary cLibrary = CLibrary.INSTANCE;
int getpid = cLibrary.getpid();
System.out.println("Process ID: " + getpid);
System.out.println("------");
String path = cLibrary.getenv("PATH");
System.out.println(path);
}
}
Result:
Process ID: 10228
------
/opt/homebrew/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin
Process finished with exit code 0
Ми бачимо, що виклик нативної функції відбувається так само, як і виклик звичайного методу.
Важливо пам'ятати, що використання нативних бібліотек з Java може зробити ваш код менш переносимим і більш схильним до помилок, оскільки він стає залежним від деталей конкретної операційної системи та архітектури процесора. Тому, цей механізм потрібно використовувати обережно.
Які програми використовують JNA?
Intellij IDEA, Elasticsearch, Apache NetBeans IDE, Apache Cassandra, OSHI та інші.
libc є стандартною бібліотекою C в багатьох системах, основаних на Unix, включаючи Linux та macOS. Вона містить багато стандартних функцій мови C, таких як введення/виведення, робота з рядками, математичні функції тощо.