2009-12-13 8 views
8

Używam niedawno wydany GlassFish v3 i podczas korzystania z bibliotek natywnych GlassFish będzie sporadycznie skarżą GlassFish loading natywne biblioteki (.dll, .so)

glassfish SEVERE: java.lang.UnsatisfiedLinkError: 
Native Library already loaded in another classloader

procedurę, aby załadować biblioteki rodzime w poprzednim wydaniu GlassFish (v2. 2) było po prostu umieścić pliki .dll w GLASSFISH_HOME \ lib. Teraz nie wiem, czy istnieje taki magiczny folder w wersji 3 i czy jest coś do powiedzenia. Sprawdziłem także ekran administratora i są dwie zmienne, które moim zdaniem są związane z moim problemem: prefiks ścieżki biblioteki rodzimej i przyrostek ścieżki biblioteki rodzimej. Przeszukuję internet, aby znaleźć odpowiedni opis tego, co oni robią i jak powinienem ich używać, ale najwyraźniej nikt nie lubi o nich rozmawiać.

Odpowiedz

3

Pierwsza rzecz: daną klasę macierzystą można załadować tylko do jednego programu ładującego klasy.

Druga sprawa: każda aplikacja internetowa w kontenerze serwletów ma własny program ładujący klasy.

Po trzecie: musisz być bardzo ostrożny przy kodowaniu natywnego kodu, aby umożliwić zbieranie klas.

Wynik: po załadowaniu kodu natywnego do aplikacji webowej najprawdopodobniej otrzymasz te błędy, jeśli spróbujesz je rozładować i ponownie załadować.

W pewnym stopniu pomijam naprawdę prostą odmianę tego tematu: wystarczy załadować dwa różne aplikacje internetowe z tą samą rodzimą klasą.

Niektórzy wolą ładować natywny kod w programie ładującym klasy systemu, aby uniknąć tego problemu.

4
java.lang.UnsatisfiedLinkError: Native Library already loaded in another classloader 

Pochodzący lib mogą być ładowane tylko raz w JVM, a otrzymasz ten komunikat o błędzie, gdy włożysz nową wersję klasy wywołującego (klasa w której znajduje się wezwanie System.loadLibrary(String)) na redeploy. Więcej na ten temat poniżej.

Procedura ładowania bibliotek rodzimych w poprzednim wydaniu glassfish (v2.2) polegała na po prostu umieszczeniu plików .dll w GLASSFISH_HOME\lib.

Cóż, to właściwie tylko pierwsza część historii. Aby załadować natywną bibliotekę, musisz oczywiście umieścić ją na ścieżce biblioteki i, aby załadować ją z kodu Java. Aby to zrobić, konwencja jest włączenie statycznego inicjatora takiego:

class FooWrapper { 
    static { 
     System.loadLibrary("foo"); 
    } 

    native void doFoo(); 
    } 
} 

Zakładając, że pracujesz z aplikacji internetowych, najlepszym rozwiązaniem jest, aby nie umieszczać rodzime biblioteki lub ich interfejsy JNI pod WEB-INF/lib lub WEB-INF/classes do unikaj problemów przy ponownym ładowaniu aplikacji, jak wspomniano powyżej. Innymi słowy, klasa, która wywołuje System.loadLibrary(String), powinna być ładowana przez moduł ładujący klasy, na który nie ma wpływu ponowne ładowanie samej aplikacji sieciowej.

Moje pytanie brzmi: gdzie umieściłeś ten kod?

PS: Inną opcją byłoby sprawdzenie, czy dll jest już dostępna przed załadowaniem, ale nie zrobiłbym tego.