Санкт-Петербургская группа тестирования JVM


« James Gozling полети... | Main | Объявление: Java... »
20060411 вторник Апрель 11, 2006

Разработка native методов в программах на Java

Native-метод — это метод Java-программы, реализация которого написана на C/C++. Это может понадобиться, например, для доступа к определенным функциям операционной системы, сторонним библиотекам на C/C++ из Java. Множество методов из Java API, взаимодействующих с операционной системой реализовано именно таким образом. Конечно же, стандартная библиотека предоставляет много возможностей, и библиотеки других производителей не отстают, однако разработчикам прикладных программ нужна возможность взаимодействия через native-методы. Не стоит, однако, забывать, что если вы реализуете функциональность с помощью native-методов, вам может протребоваться собрать C/C++ библиотеку для нескольких операционных систем. Не забывайте об основном принципе Java — WORA: Write Once, Run Anywhere.

Давайте рассмотрим пример реализации native-метода. Интерфейс с такими методами называется Java Native Interface (JNI). Предположим, что нужно написать метод, отображающий информацию о текущем состоянии JVM — стеки всех нитей, состояние памяти, и т.д. Точнее, сама JVM умеет выводить такую информацию и вы можете увидеть ее нажав Ctrl-\ на Unix системах или Ctrl-Break на Windows системах. А мы создадим метод, заставляющий JVM это сделать без вмешательства пользователя.

Пишем часть на Java.

JavaDump.java:

public class JavaDump {
    static {
        System.loadLibrary("JavaDump");
    }

    /**
     * Send SIGQUIT to java process and Ctrl-Break on Windows.
     * This will usually cause JVM to dump information about
     * current state.
     *
     * @return true if it was successful
     * 
     */
    public static native boolean javaDump();

    public static void main(String[] args) {
        javaDump();
    }
}

Метод, который будет реализован на C объявляется native. В статическом инициализаторе загружается библиотека, которая будет содержать ревлизацию этого метода. Для unix-систем это будет libJavaDump.so, для Windows - JavaDump.dll.

Компилируем этот класс javac:

> javac JavaDump.java

Используем javah для получения заголовочного файла с объявлением функции javaDump:

> javah JavaDump

Получается файл JavaDump.h:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JavaDump */
#ifndef _Included_JavaDump
#define _Included_JavaDump
#ifdef __cplusplus
extern "C" { #endif /*  * Class: JavaDump  * Method: javaDump  * Signature: ()Z  */ JNIEXPORT jboolean JNICALL Java_JavaDump_javaDump  (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif

Пишем реализацию этого метода. На Unix-системах будем использовать сигнал SIGQUIT, а на Windows — функцию GenerateConsoleCtrlEvent.

JavaDump.c:

#include "jni.h"
#ifdef _WIN32
#include <windows.h>
#else /* _WIN32 */
#include <unistd.h>
#include <signal.h>
#endif /* _WIN32 */

JNIEXPORT jboolean JNICALL Java_JavaDump_javaDump
(JNIEnv *env, jclass clazz) {

#ifdef _WIN32
    int dw;
    LPVOID lpMsgBuf;
    if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
        dw = GetLastError();
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, 
                      dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
	              (LPTSTR) &lpMsgBuf,
	              0,
	              NULL);

        printf("%s\n", lpMsgBuf);
        LocalFree(lpMsgBuf);
        return JNI_FALSE;
    }

   return JNI_TRUE;

#else /* if not _WIN32 */

   kill(getpid(), SIGQUIT);
   return JNI_TRUE;

#endif /* _WIN32 */
}

Теперь нужно собрать библиотеку для каждой архитектуры. Для каждой архитектуры будем собирать в отдельный каталог. Пусть JDK установлена в /opt/sun-jdk-1.6.0 или C:\Program Files\Java\jdk1.6.0.

Для Linux на архитектуре Intel:

> mkdir linux-i586
> gcc -I/opt/sun-jdk-1.6.0/include -I/opt/sun-jdk-1.6.0/include/linux -shared -fPIC
      JavaDump.c -o linux-i586/libJavaDump.so

Для Solaris на архитектуре SPARC:

> mkdir solaris-sparc
> cc -G -KPIC -I/usr/java/include -I/usr/java/include/solaris
     JavaDump.c -o solaris-sparc/libJavaDump.so

Для Windows на Intel архитектуре:

> mkdir windows-i586
> cl /LD /MD
     /I"C:\Program Files\Java\jdk1.6.0\include"
     /I"C:\Program Files\Java\jdk1.6.0\include\win32"
     JavaDump.c 
     /Fewindows-i586/JavaDump.dll

Запускаем:

На Linux-Intel:

> LD_LIBRARY_PATH=linux-i586 java JavaDump

На Solaris-SPARC:

> LD_LIBRARY_PATH=solaris-sparc java javaDump

На Windows:

> set PATH=window-i586;%PATH%
> java JavaDump

Работает.

Но нам пришлось делать одни и те же действия для каждой архитектуры. Все-таки на Java писать проще. Тем более, что большинство получаемой информации доступно и через JVM Monitoring and Management API.

Все, что здесь описано - это, конечно, один из самых простых случаев. Есть много нюансов, о которых можно прочитать по ссылкам:

Удачи Вам!

Н.Х.

опубликовал vmrobot ( апр 11 2006, 07:22:06 PM MSD ) Permalink Комментарии [0]

Trackback URL: http://blogs.sun.com/vmrobot/entry/%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5_native_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D0%BE%D0%B2_%D0%B2_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0%D1%85
Комментарии:

Опубликовать комментарий:

Имя
E-Mail:
URL:

Ваш комментарий:

HTML Syntax: Отключен

Хиты страниц за сегодня: 120