Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации

API Вызова


 Глава 5

API Вызова позволяет поставщикам программного обеспечения загружать Java VM в произвольное собственное приложение. Поставщики могут поставить поддерживающие Java приложения, не имея необходимость соединять с Java исходный код VM.

Эта глава начинается с краткого обзора API Вызова. Это сопровождается ссылочными страницами для всех API-функций Вызова.

Чтобы улучшить возможность встраивания Java VM, API Вызова расширяется в JDK 1.1.2 несколькими незначительными способами.

Краткий обзор

Следующий пример кода иллюстрирует, как использовать функции в API Вызова. В этом примере код C++ создает Java VM и вызывает статический метод, вызванный Main.test. Для ясности мы опускаем проверку на ошибки.


    #include <jni.h>       /* where everything is defined */
    ...
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JDK1_1InitArgs vm_args; /* JDK 1.1 VM initialization arguments */
    vm_args.version = 0x00010001; /* New in 1.1.2: VM version */
    /* Get the default initialization arguments and set the class 
     * path */
    JNI_GetDefaultJavaVMInitArgs(&vm_args);
    vm_args.classpath = ...;
    /* load and initialize a Java VM, return a JNI interface 
     * pointer in env */
    JNI_CreateJavaVM(&jvm, &env, &vm_args);
    /* invoke the Main.test method using the JNI */
    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
    env->CallStaticVoidMethod(cls, mid, 100);
    /* We are done. */
    jvm->DestroyJavaVM();

Этот пример использует три функции в API. API Вызова позволяет собственному приложению использовать указатель на интерфейс JNI для доступа функции VM. Проект подобен JRI Netscape, Встраивающему Интерфейс.

Создание VM

JNI_CreateJavaVM() функционируйте загружает и инициализирует Java VM и возвращает указатель на указатель на интерфейс JNI. Поток, который вызывал JNI_CreateJavaVM() как полагают, основной поток.

Присоединение к VM

Указатель на интерфейс JNI (JNIEnv) допустимо только в текущем потоке. Если другой поток должен получить доступ к Java VM, это должно сначала вызвать AttachCurrentThread() присоединиться к VM и получить указатель на интерфейс JNI. После того, как присоединенный к VM, собственный поток работает точно так же как обычное выполнение потока Java в собственном методе. Собственный поток остается присоединенным к VM, пока это не вызывает DetachCurrentThread() отсоединять себя.

У присоединенного потока должно быть достаточное стековое пространство, чтобы выполнить reaonable объем работы. Выделение стекового пространства на поток работает специфичный для системы. Например, используя pthreads, размер стека может быть определен в pthread_attr_t параметр pthread_create.

Разгрузка VM

Основной поток не может отсоединить себя от VM. Вместо этого это должно вызвать DestroyJavaVM() разгрузить весь VM.

VM ожидает, пока основной поток не является единственным пользовательским потоком прежде, чем это фактически разгрузится. Пользовательские потоки включают и потоки Java и присоединили собственные потоки. Это ограничение существует, потому что поток Java или присоединил собственный поток, может содержать системные ресурсы, такие как блокировки, окна, и так далее. VM не может автоматически освободить эти ресурсы. Ограничивая основной поток, чтобы быть единственным рабочим потоком, когда VM разгружается, бремя выпуска системных ресурсов, сохраненных произвольными потоками, находится на программисте.

Структуры инициализации

Различный Java реализация VM, вероятно, потребует различных параметров инициализации. Трудно придумать стандартную структуру инициализации, подходящую для всего настоящего и будущего Java VMs. Как компромисс, мы резервируем первое поле (версия), чтобы идентифицировать контент структуры инициализации. Собственные приложения, встраивающие JDK 1.1.2, должны установить поле версии в 0x00010001. Реализации VM поощряются использовать ту же самую структуру инициализации в качестве JDK, хотя другие реализации могут хотеть игнорировать некоторые из параметров инициализации, поддерживаемых JDK.

Номера версий 0x80000000 к 0xFFFFFFFF резервируются, и не должны быть распознаны никакой реализацией VM.

Следующий код показывает структуру, используемую, чтобы инициализировать Java VM в JDK 1.1.2.


typedef struct JDK1_1InitArgs {
   /* The first two fields were reserved in JDK 1.1, and
      formally introduced in JDK 1.1.2. */
   /* Java VM version */
    jint version;
   /* System properties. */
    char **properties;
   /* whether to check the Java source files are newer than 
    * compiled class files. */
    jint checkSource;
   /* maximum native stack size of Java-created threads. */
    jint nativeStackSize;
   /* maximum Java stack size. */
    jint javaStackSize;
   /* initial heap size. */
    jint minHeapSize;
   /* maximum heap size. */
    jint maxHeapSize;
   /* controls whether Java byte code should be verified:
    * 0 -- none, 1 -- remotely loaded code, 2 -- all code. */
    jint verifyMode;
   /* the local directory path for class loading. */
    const char *classpath;
   /* a hook for a function that redirects all VM messages. */
    jint (*vfprintf)(FILE *fp, const char *format, 
                     va_list args);
   /* a VM exit hook. */
    void (*exit)(jint code);
   /* a VM abort hook. */
    void (*abort)();
   /* whether to enable class GC. */
    jint enableClassGC;
   /* whether GC messages will appear. */
    jint enableVerboseGC;
   /* whether asynchronous GC is allowed. */
    jint disableAsyncGC;
   /* Three reserved fields. */ 
    jint reserved0;
    jint reserved1;
    jint reserved2;
} JDK1_1InitArgs;

В JDK 1.1.2, структура инициализации обеспечивает рычаги так, чтобы собственное приложение могло перенаправить сообщения VM и получить управление, когда VM завершается.

Структуру ниже передают как параметр, когда собственный поток присоединяет к Java VM в JDK 1.1.2. В действительности никакие параметры не требуются для собственного потока присоединить к JDK 1.1.2. JDK1_1AttachArgs структура состоит только из дополнительного слота для тех компиляторов C, которые не разрешают пустые структуры.


typedef struct JDK1_1AttachArgs {
   /*
    * JDK 1.1 does not need any arguments to attach a
    * native thread. The padding is here to satisfy the C
    * compiler which does not permit empty structures.
    */
    void *__padding;
} JDK1_1AttachArgs;

Библиотека и управление Версией

В JDK 1.1, как только собственная библиотека загружается, это видимо от всех загрузчиков class. Поэтому два класса в различных загрузчиках class могут соединиться с тем же самым собственным методом. Это приводит к двум проблемам:
  • class может по ошибке соединиться с собственными библиотеками, загруженными class тем же самым именем в различном загрузчике class.
  • Собственные методы могут легко смешать классы от различных загрузчиков class. Это повреждает разделение пространства имен, предлагаемое загрузчиками class, и приводит к проблемам безопасности типов.

В Java 2 SDK каждый загрузчик class управляет своим собственным набором собственных библиотек. Тот же самый JNI собственная библиотека не может быть загружен больше чем в один загрузчик class. Выполнение так причины UnsatisfiedLinkError быть брошенным. Например, System.loadLibrary броски UnsatisfiedLinkError когда использующийся загрузить собственную библиотеку в два загрузчика class. Преимущества нового подхода:

  • Разделение пространства имен, основанное на загрузчиках class, сохраняется в собственных библиотеках. Собственная библиотека не может легко смешать классы от различных загрузчиков class.
  • Кроме того, собственные библиотеки могут быть разгружены, когда их соответствующие загрузчики class собираются "мусор".

Чтобы облегчить управление управлением версиями и управление ресурсами, библиотеки JNI в Java, 2 Платформы могут дополнительно экспортировать следующие две функции:

JNI_OnLoad

jint JNI_OnLoad(JavaVM *vm, void *reserved);

Вызовы VM JNI_OnLoad когда собственная библиотека загружается (например, через System.loadLibrary). JNI_OnLoad должен возвратить версию JNI, необходимую собственной библиотеке.

Чтобы использовать любую из новых функций JNI, собственная библиотека должна экспортировать a JNI_OnLoad функция, которая возвращается JNI_VERSION_1_2. Если собственная библиотека не экспортирует a JNI_OnLoad функция, VM предполагает, что библиотека только требует версии JNI JNI_VERSION_1_1. Если VM не распознает номер версии, возвращенный JNI_OnLoad, собственная библиотека не может быть загружена.

РЕДАКТИРОВАНИЕ:

Экспортируемый от собственных библиотек, которые содержат собственную реализацию метода.

НАЧИНАЯ С SDK/JRE 1.4:

Чтобы использовать функции JNI, представленные в выпуске 1.2 J2SE, в дополнение к тем, которые были доступны в JDK 1.1, собственная библиотека должна экспортировать a JNI_OnLoad функция, которая возвращается JNI_VERSION_1_2.

Чтобы использовать функции JNI, представленные в выпуске 1.4 J2SE, в дополнение к тем, которые были доступны в выпуске 1.2, собственная библиотека должна экспортировать a JNI_OnLoad функция, которая возвращается JNI_VERSION_1_4.

Если собственная библиотека не экспортирует a JNI_OnLoad функция, VM предполагает, что библиотека только требует версии JNI JNI_VERSION_1_1. Если VM не распознает номер версии, возвращенный JNI_OnLoad, собственная библиотека не может быть загружена.

JNI_OnUnload

void JNI_OnUnload(JavaVM *vm, void *reserved);

Вызовы VM JNI_OnUnload когда загрузчик class, содержащий собственную библиотеку, собирается "мусор". Эта функция может использоваться, чтобы выполнить операции уборки. Поскольку эта функция вызывается в неизвестном контексте (такой как от финализатора), программист должен быть консервативным при использовании Java службы VM, и рефрен от произвольных обратных вызовов Java.

Отметьте это JNI_OnLoad и JNI_OnUnload две функции, дополнительно предоставленные библиотеками JNI, не экспортируемыми от VM.

РЕДАКТИРОВАНИЕ:

Экспортируемый от собственных библиотек, которые содержат собственную реализацию метода.

API-функции вызова

JavaVM тип является указателем на таблицу API-функции Вызова. Следующий пример кода показывает эту функциональную таблицу.


typedef const struct JNIInvokeInterface *JavaVM;


const struct JNIInvokeInterface ... = { 
    NULL, 
    NULL, 
    NULL, 
 
    DestroyJavaVM, 
    AttachCurrentThread, 
    DetachCurrentThread, 

    GetEnv,

    AttachCurrentThreadAsDaemon
};


Отметьте что три API-функции Вызова, JNI_GetDefaultJavaVMInitArgs(), JNI_GetCreatedJavaVMs(), и JNI_CreateJavaVM(), не часть таблицы функции JavaVM. Эти функции могут использоваться без существования ранее JavaVM структура.

JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);

Возвращает конфигурацию значения по умолчанию для Java VM. Прежде, чем вызвать эту функцию, набор собственного кода must1 vm_args-> поле версии к версии JNI это ожидает, что VM будет поддерживать. В JDK 1.1.2, vm_args-> версия должна быть установлена в 0x00010001. После этой функции возвраты vm_args-> версия будет установлена в фактическую версию JNI, которую поддерживает VM.

РЕДАКТИРОВАНИЕ:

Экспортируемый от собственной библиотеки, которая реализует виртуальную машину Java.

ПАРАМЕТРЫ:

vm_args: указатель на a VM-specific initialization структура в, к которому параметры по умолчанию заполнены.

ВОЗВРАТЫ:

Возвраты “0”, если требуемая версия поддерживается; возвращает отрицательное число, если требуемая версия не поддерживается.

JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen,
jsize *nVMs);

Возвраты весь Java VMs, которые были созданы. Указатели на VMs пишутся в буфере vmBuf в порядке, они создаются. В большинстве bufLen числа записей будет записан. Общее количество создаваемого VMs возвращается в *nVMs.

JDK 1.1.2 не поддерживает создание больше чем одного VM в единственном процессе.

РЕДАКТИРОВАНИЕ:

Экспортируемый от собственной библиотеки, которая реализует виртуальную машину Java.

ПАРАМЕТРЫ:

vmBuf: указатель на буфер, куда структуры VM будут помещены.

bufLen: длина буфера.

nVMs: указатель на целое число.

ВОЗВРАТЫ:

Возвраты “0” на успехе; возвращает отрицательное число при отказе.

JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args);

Загрузки и инициализируют Java VM. Текущий поток становится основным потоком. Наборы env параметр указателю на интерфейс JNI основного потока.

JDK 1.1 не поддерживает создание больше чем одного VM в единственном процессе. Поле версии в vm_args must2 быть установленным в 0x00010001.

В JDK 1.1, втором параметре JNI_CreateJavaVM всегда указатель на JNIEnv *. Третьим параметром является указатель на JDK 1.1 определенных структуры (JDK1_1InitArgs). JDK1_1InitArgs структура ясно не разрабатывается, чтобы быть переносимой на всем VMs.

В Java 2 SDK мы представляем стандартную структуру инициализации VM. Обратная совместимость сохраняется. Если параметр инициализации VM указывает на a JDK1_1InitArgs структура, JNI_CreateJavaVM все еще возвращает 1.1 версии указателя на интерфейс JNI. VM возвращает 1.2 версии указателя на интерфейс JNI, если третий параметр указывает на a JavaVMInitArgs структура. В отличие от этого JDK1_1InitArgs, который содержит фиксированный набор опций, JavaVMInitArgs опция использования представляет в виде строки, чтобы закодировать произвольные опции запуска VM.

typedef struct JavaVMInitArgs {
    jint version;

    jint nOptions;
    JavaVMOption *options;
    jboolean ignoreUnrecognized;
} JavaVMInitArgs;

version поле должно быть установлено в JNI_VERSION_1_2. (Напротив, поле версии в JDK1_1InitArgs должен быть установлен в JNI_VERSION_1_1.) options поле является массивом следующего типа:

typedef struct JavaVMOption {
    char *optionString;
    void *extraInfo;
} JavaVMOption;

Размер массива обозначается nOptions полем в JavaVMInitArgs. Если ignoreUnrecognized JNI_TRUE, JNI_CreateJavaVM проигнорируйте все нераспознанные строки опции, которые начинаются"-X"или"_". Если ignoreUnrecognized JNI_FALSE, JNI_CreateJavaVM возвраты JNI_ERR как только это встречается с любыми нераспознанными строками опции. Весь Java VMs должен распознать следующий набор стандартных опций:

optionString значение
-D<name>=<value> Установите системное свойство
-verbose[:class|gc|jni] Включите многословному выводу. Опции могут сопровождаться списком разделенных запятой значений имен, указывающих, какие сообщения будут напечатаны VM. Например,"-verbose:gc,class"дает VM команду печатать GC и class, загружающий похожие сообщения. Стандартные имена включают: gc, class, и jni. Все нестандартное (VM-specific) имена должно начаться"X".
vfprintf extraInfo указатель на vfprintf рычаг.
exit extraInfo указатель на exit рычаг.
abort extraInfo указатель на abort рычаг.

 

Кроме того, каждая реализация VM может поддерживать свой собственный набор нестандартных строк опции. Нестандартные имена опции должны начаться"-X"или подчеркивание ("_"). Например, Java 2 SDK поддерживает -Xms и -Xmx опции, чтобы позволить программистам определяют начальный и максимальный размер "кучи". Опции, которые начинаются"-X"доступны от"java"командная строка.

Вот пример кода, который создает Java VM в Java 2 SDK:

JavaVMInitArgs vm_args;
JavaVMOption options[4];

options[0].optionString = "-Djava.compiler=NONE";           /* disable JIT */
options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */
options[2].optionString = "-Djava.library.path=c:\mylibs";  /* set native library path */
options[3].optionString = "-verbose:jni";                   /* print JNI-related messages */

vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = TRUE;

/* Note that in the Java 2 SDK, there is no longer any need to call 
 * JNI_GetDefaultJavaVMInitArgs. 
 */
res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
if (res < 0) ...

Java 2 SDK все еще поддерживает JDK1_1InitArgs точно таким же образом как JDK 1.1.

РЕДАКТИРОВАНИЕ:

Экспортируемый от собственной библиотеки, которая реализует виртуальную машину Java.

ПАРАМЕТРЫ:

p_vm: указатель на расположение, куда получающаяся структура VM будет помещена.

p_env: указатель на расположение, куда указатель на интерфейс JNI для основного потока будет помещен.

vm_args: Java параметры инициализации VM.

ВОЗВРАТЫ:

Возвраты “0” на успехе; возвращает отрицательное число при отказе.

DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm);

Разгружает Java VM и исправляет его ресурсы. Только основной поток может разгрузить VM. Система ожидает, пока основной поток только не остается пользовательским потоком прежде, чем это уничтожит VM.

Поддержка DestroyJavaVM не было полно в 1.1. Только основной поток может вызвать DestroyJavaVM. В Java 2 SDK любой поток, или присоединенный или нет, может вызвать эту функцию. Если текущий поток присоединяется, VM ожидает, пока текущий поток не является единственным потоком Java на уровне пользователя. Если текущий поток не присоединяется, VM присоединяет текущий поток и затем ожидает, пока текущий поток не является единственным потоком на уровне пользователя. Java 2 SDK все еще не поддерживает разгрузку VM, как бы то ни было. DestroyJavaVM всегда возвращает код ошибки.

РЕДАКТИРОВАНИЕ:

Индексируйте 3 в таблице функции интерфейса JavaVM.

ПАРАМЕТРЫ:

vm: VM Java, который будет уничтожен.

ВОЗВРАТЫ:

Возвраты “0” на успехе; возвращает отрицательное число при отказе.

JDK 1.1.2 не поддерживает разгрузку VM.

AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, JNIEnv **p_env, void *thr_args);

Присоединяет текущий поток к Java VM. Возвращает указатель на интерфейс JNI в JNIEnv параметр.

Попытка присоединить поток, который уже присоединяется, нет.

Собственный поток не может быть присоединен одновременно к двум Java VMs.

Когда поток присоединен к VM, контексту, загрузчик class является программой начальной загрузки.

РЕДАКТИРОВАНИЕ:

Индексируйте 4 в таблице функции интерфейса JavaVM.

ПАРАМЕТРЫ:

vm: VM, к которому будет присоединен текущий поток.

p_env: указатель на расположение, куда указатель на интерфейс JNI текущего потока будет помещен.

thr_args: VM-specific распараллеливают присоединяемые параметры.

В JDK 1.1, втором параметре AttachCurrentThread всегда указатель на JNIEnv. Третий параметр AttachCurrentThread был зарезервирован, и должен быть установлен в NULL.

В Java 2 SDK Вы передаете NULL как третий параметр за 1.1 поведения, или передача указатель на следующую структуру, чтобы определить дополнительную информацию:

typedef struct JavaVMAttachArgs {
    jint version;  /* must be JNI_VERSION_1_2 */
    char *name;    /* the name of the thread, or NULL */
    jobject group; /* global ref of a ThreadGroup object, or NULL */
} JavaVMAttachArgs

ВОЗВРАТЫ:

Возвраты “0” на успехе; возвращает отрицательное число при отказе.

AttachCurrentThreadAsDaemon

jint AttachCurrentThreadAsDaemon(JavaVM* vm, void** penv, void* args);

Та же самая семантика как AttachCurrentThread, но недавно создаваемый экземпляр java.lang.Thread является демоном.

Если поток был уже присоединен или через AttachCurrentThread или через AttachCurrentThreadAsDaemon, эта подпрограмма просто устанавливает значение, на которое указывает penv к JNIEnv текущего потока. В этом случае ни AttachCurrentThread, ни эта подпрограмма не имеют эффекта на состояние демона потока.

РЕДАКТИРОВАНИЕ:

Индексируйте 7 в таблице функции интерфейса JavaVM.

ПАРАМЕТРЫ:

vm: экземпляр виртуальной машины, к которому будет присоединен текущий поток.

penv: указатель на расположение, в которое будет помещен указатель на интерфейс JNIEnv для текущего потока.

args: указатель на структуру JavaVMAttachArgs.

ВОЗВРАТЫ

Возвраты обнуляют на успехе; иначе, возвращает отрицательное число.

ИСКЛЮЧЕНИЯ

Ни один.

С ТЕХ ПОР:

SDK/JRE 1.4

DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm);

Отсоединяет текущий поток от Java VM. Выпускаются все мониторы Java, сохраненные этим потоком. Уведомляются все потоки Java, ожидающие этого потока, чтобы умереть.

В JDK 1.1, основной поток не может быть отсоединен от VM. Это должно вызвать DestroyJavaVM разгрузить весь VM.

В Java 2 SDK основной поток может быть отсоединен от VM.

Основной поток, который является потоком, который создал Java VM, не может быть отсоединен от VM. Вместо этого основной поток должен вызвать JNI_DestroyJavaVM() разгрузить весь VM.

РЕДАКТИРОВАНИЕ:

Индексируйте 5 в таблице функции интерфейса JavaVM.

ПАРАМЕТРЫ:

vm: VM, от которого будет отсоединен текущий поток.

ВОЗВРАТЫ:

Возвраты “0” на успехе; возвращает отрицательное число при отказе.

GetEnv

jint GetEnv(JavaVM *vm, void **env, jint version);

РЕДАКТИРОВАНИЕ:

Индексируйте 6 в таблице функции интерфейса JavaVM.

ВОЗВРАТЫ:

Если текущий поток не присоединен к VM, наборам *env к NULL, и возвраты JNI_EDETACHED. Если указанная версия не поддерживается, наборы *env к NULL, и возвраты JNI_EVERSION. Иначе, наборы *env к соответствующему интерфейсу, и возвратам JNI_OK.

ПАРАМЕТРЫ:

vm: Экземпляр виртуальной машины, от которого будет получен интерфейс.
env: указатель на расположение, куда указатель на интерфейс JNI для текущего потока будет помещен.
version: Требуемая версия JNI.

 

_________________________

1. JDK 1.1 не требовал, чтобы собственный код установил поле версии. Для обратной совместимости JDK 1.1.2 предполагает, что требуемая версия является 0x00010001, если поле версии не устанавливается. Будущие версии JDK потребуют, чтобы поле версии было установлено в соответствующее значение.

2. См. сноску 1.


Содержание | Предыдущий

Oracle и/или его филиалы Авторское право © 1993, 2012, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами