Co to jest Java ClassLoader?

174

W kilku prostych zdaniach, czym jest Java ClassLoader, kiedy jest używany i dlaczego?

OK, przeczytałem artykuł na wiki. ClassLoader ładuje klasy. DOBRZE. Więc jeśli dołączę pliki jar i zaimportuję, ClassLoader wykona zadanie.

Dlaczego mam zawracać sobie głowę tym ClassLoaderem? Nigdy go nie używałem i nie wiedziałem, że istnieje.

Pytanie brzmi, dlaczego istnieje klasa ClassLoader? A także, jak wykorzystujesz to w praktyce? (Wiem, że istnieją przypadki).

EugeneP
źródło
Lepsze wyniki uzyskasz, jeśli zawęzisz swoje pytanie, np. Wskazując konkretną część, której nie rozumiesz, jak odnosi się ona do innego języka, który znasz, itp.
JRL
75
To całkiem rozsądne pytanie, patrząc z perspektywy kogoś, kto szuka kilku prostych zdań wyjaśniających koncepcję
oxbow_lakes
Ten film może Cię zainteresować: Czy naprawdę
asmaier

Odpowiedzi:

231

Zaczerpnięte z tego fajnego samouczka Sun:

Motywacja

Aplikacje napisane w statycznie skompilowanych językach programowania, takich jak C i C ++, są kompilowane w natywne, specyficzne dla maszyny instrukcje i zapisywane jako plik wykonywalny. Proces łączenia kodu w wykonywalny kod natywny nazywa się łączeniem - łączeniem oddzielnie skompilowanego kodu z kodem biblioteki współdzielonej w celu utworzenia wykonywalnej aplikacji. Inaczej jest w przypadku dynamicznie kompilowanych języków programowania, takich jak Java. W języku Java pliki .class generowane przez kompilator języka Java pozostają niezmienione do momentu załadowania do wirtualnej maszyny języka Java (JVM) - innymi słowy, proces łączenia jest wykonywany przez maszynę JVM w czasie wykonywania. Klasy są ładowane do maszyny JVM na zasadzie „w razie potrzeby”. A kiedy załadowana klasa zależy od innej klasy, to ta klasa również jest ładowana.

Po uruchomieniu aplikacji Java pierwszą klasą do uruchomienia (lub punktem wejścia do aplikacji) jest ta z publiczną statyczną metodą void o nazwie main (). Ta klasa zwykle zawiera odwołania do innych klas, a wszystkie próby załadowania klas, do których się odwołuje, są wykonywane przez program ładujący klasy.

Aby zapoznać się z rekurencyjnym ładowaniem klas, a także ogólnie z ideą ładowania klas, rozważ następującą prostą klasę:

public class HelloApp {
   public static void main(String argv[]) {
      System.out.println("Aloha! Hello and Bye");
   }
}

Jeśli uruchomisz tę klasę, podając opcję wiersza polecenia -verbose: class, aby wypisała, jakie klasy są ładowane, otrzymasz dane wyjściowe, które wyglądają następująco. Zauważ, że jest to tylko część wyniku, ponieważ lista jest zbyt długa, aby ją tutaj pokazać.

prmpt>java -verbose:class HelloApp



[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

Jak widać, najpierw ładowane są klasy środowiska uruchomieniowego Java wymagane przez klasę aplikacji (HelloApp).

Moduły ładujące klasy na platformie Java 2

Język programowania Java stale ewoluuje, aby codziennie ułatwiać życie programistom aplikacji. Odbywa się to poprzez udostępnianie interfejsów API, które upraszczają życie, umożliwiając skoncentrowanie się na logice biznesowej, a nie na szczegółach implementacji podstawowych mechanizmów. Jest to widoczne po niedawnej zmianie J2SE 1.5 na J2SE 5.0 w celu odzwierciedlenia dojrzałości platformy Java.

Od wersji JDK 1.2 program ładujący klasy ładowania początkowego wbudowany w maszynę JVM jest odpowiedzialny za ładowanie klas środowiska wykonawczego Java. Ten program ładujący klasy ładuje tylko klasy, które znajdują się w ścieżce startowej klasy, a ponieważ są to klasy zaufane, proces sprawdzania poprawności nie jest wykonywany, jak w przypadku klas niezaufanych. Oprócz modułu ładującego klasy ładujące, maszyna JVM ma moduł ładujący klasy rozszerzeń odpowiedzialny za ładowanie klas ze standardowych interfejsów API rozszerzeń oraz moduł ładujący klasy systemowe, który ładuje klasy z ogólnej ścieżki klas, a także klas aplikacji.

Ponieważ istnieje więcej niż jeden program ładujący klasy, są one reprezentowane w drzewie, którego korzeniem jest program ładujący klasy ładowania początkowego. Każdy program ładujący klasy ma odniesienie do swojego programu ładującego klasy nadrzędnej. Kiedy program ładujący klasy jest proszony o załadowanie klasy, konsultuje się z programem ładującym klasę nadrzędną przed próbą załadowania samego elementu. Rodzic z kolei konsultuje się ze swoim rodzicem i tak dalej. Tak więc tylko wtedy, gdy wszystkie programy ładujące klas przodków nie mogą znaleźć klasy, w którą zaangażowany jest bieżący program ładujący klas. Innymi słowy, używany jest model delegacji.

Klasa java.lang.ClassLoader

java.lang.ClassLoaderJest klasą abstrakcyjną, która może być podklasy przez aplikacje, które muszą rozciągać się, w jaki sposób JVM dynamicznie ładuje klas. Konstruktory w java.lang.ClassLoader(i jego podklasy) umożliwiają określenie rodzica podczas tworzenia instancji nowego programu ładującego klasy. Jeśli nie określisz jawnie elementu nadrzędnego, moduł ładujący klasy systemowej maszyny wirtualnej zostanie przypisany jako domyślny element nadrzędny. Innymi słowy, klasa ClassLoader używa modelu delegowania do wyszukiwania klas i zasobów. W związku z tym każde wystąpienie klasy ClassLoader ma skojarzony moduł ładujący klasy nadrzędnej, dzięki czemu w przypadku żądania znalezienia klasy lub zasobów zadanie jest delegowane do programu ładującego klasy nadrzędnej przed próbą znalezienia samej klasy lub zasobu. loadClass()Sposób classloader wykonuje następujące zadania, w porządku, gdy nazwie się załadować klasę:

Jeśli klasa została już załadowana, zwraca ją. W przeciwnym razie deleguje wyszukiwanie nowej klasy do programu ładującego klasy nadrzędnej. Jeśli moduł ładujący klasy nadrzędnej nie znajdzie klasy, loadClass()wywołuje metodę w findClass()celu znalezienia i załadowania klasy. W finalClass()sposób wyszukuje klasy w bieżącym ładującego klasy, jeśli klasa nie została znaleziona przez loader klasy nadrzędnej.


Więcej znajduje się w oryginalnym artykule, który pokazuje również, jak zaimplementować własne programy ładujące klasy sieci, co odpowiada na twoje pytanie, dlaczego (i jak). Zobacz także dokumentację API .

JRL
źródło
47

Większość programistów Java nigdy nie będzie musiała jawnie używać programów ładujących klasy (z wyjątkiem ładowania zasobów, aby nadal działały, gdy są dołączone do plików JAR), nie mówiąc już o pisaniu własnych.

ClassLoadery są używane w dużych systemach i aplikacjach serwerowych do:

  • Modularyzuj system i ładuj, zwalniaj i aktualizuj moduły w czasie wykonywania
  • Używaj równolegle różnych wersji biblioteki API (np. Parsera XML)
  • Izoluj różne aplikacje działające w tej samej JVM (upewniając się, że nie kolidują ze sobą, np. Poprzez zmienne statyczne)
Michael Borgwardt
źródło
29

Pytanie brzmi: „Dlaczego warto zawracać sobie głowę tą klasą ClassLoader”?

Cóż, głównie po to, abyś mógł naprawić rzeczy, jeśli pójdą źle :-).

To prawda, o ile po prostu napiszesz aplikację, skompilujesz ją do JARa i może dołączysz kilka dodatkowych bibliotek JAR, nie musisz wiedzieć o ładujących klasach, po prostu zadziała.

Mimo to warto trochę wiedzieć o programach ładujących klasy i ładowaniu klas, aby lepiej zrozumieć, co dzieje się za kulisami. Na przykład „statyczne inicjatory” będą działać po załadowaniu klasy, więc aby zrozumieć, kiedy zostaną uruchomione, musisz wiedzieć, w jaki sposób program ładujący klas decyduje, kiedy je załadować.

także… jak wykorzystujesz to w praktyce?

W prostych przypadkach ich nie potrzebujesz. Jednakże, jeśli potrzebujesz dynamicznie ładować kod w czasie wykonywania z wyraźną kontrolą skąd pochodzi (np. Ładowanie przez sieć, ładowanie wtyczek niedostępnych w czasie kompilacji itp.), Być może będziesz musiał zrobić więcej. Następnie możesz np. Napisać własny program ładujący klasy. Zobacz inne odpowiedzi na linki.

sleske
źródło
14

ClassLoaderw Javie to klasa, która służy do ładowania plików klas w Javie. Kod Java jest kompilowany do pliku klasy przez javackompilator, a JVM wykonuje program Java, wykonując kody bajtowe zapisane w pliku klas.

ClassLoader jest odpowiedzialny za ładowanie plików klas z systemu plików, sieci lub dowolnego innego źródła. Istnieją trzy domyślne programy ładujące klasy używane w Java, Bootstrap , Extension i System lub Application loader.

ClassLoader


Jak działa ClassLoader

## Interakcja ClassLoader z maszyną JVM wprowadź opis obrazu tutaj

Więcej @: how-classloader-works-in-java.html

roottraveller
źródło
6

Moduły ładujące klasy to funkcjonalny składnik maszyny JVM, który ładuje dane klas z pliku „.class” lub z sieci do obszaru metod w stercie.

Wygląda na integralną część maszyny JVM, ale jako końcowy użytkownik języka Java, dlaczego miałbym się tym przejmować? Oto dlaczego:

Każdy program ładujący klas ma własną przestrzeń nazw, a klasy wywoływane przez określony program ładujący klas trafiają do jego przestrzeni nazw.

Klasy wywoływane przez dwa różne programy ładujące klasy nie będą miały widoczności względem siebie nawzajem, co zwiększy bezpieczeństwo.

Mechanizm delegowania elementów potomnych modułu ładującego klasy zapewnia, że ​​nieautoryzowany kod nigdy nie może zostać zhakowany przez klasy API Java.

Po szczegóły zajrzyj tutaj

bitan
źródło
1

Programy ładujące klasy są hierarchiczne. Klasy są wprowadzane do maszyny JVM, ponieważ odwołuje się do nich nazwa w klasie, która już działa w maszynie JVM.

Jak załadowano pierwszą klasę?
Pierwsza klasa jest ładowana za pomocą static main()metody zadeklarowanej w Twojej klasie. Wszystkie kolejno ładowane klasy są ładowane przez klasy, które są już załadowane i uruchomione.

Program ładujący klasy tworzy przestrzeń nazw. Wszystkie maszyny JVM zawierają co najmniej jeden program ładujący klasy, który jest osadzony w JVM, nazywany podstawowym (lub ładującym) programem ładującym klasy. To jedno, a przyjrzymy się innym niż pierwotne programy ładujące klasy. Maszyna JVM zawiera zaczepy, które umożliwiają używanie programów ładujących zdefiniowane przez użytkownika zamiast pierwotnego programu ładującego klasy. Oto programy ładujące klasy utworzone przez maszynę JVM.

Bootstrap (pierwotny) Nie można ponownie załadować tego programu ładującego klasy. Ładuje wewnętrzne klasy JDK, pakiety java. * (Zazwyczaj ładuje rt.jar i i18n.jar). Rozszerzenia Nie można ponownie załadować programu ładującego tej klasy. Wczytuje pliki jar z katalogu rozszerzeń JDK (zwykle lib / ext z JRE). System Program ładujący tej klasy nie jest ponownie ładowany. Ładuje klasy ze ścieżki klas systemowych.

http://www.sbalasani.com/2015/01/java-class-loaders.html

Srinivas Balasani
źródło
1

Kiedy pytasz, dlaczego istnieje klasa ClassLoader, przyczyna jest dość prosta - jest to klasa odpowiedzialna za znajdowanie i ładowanie plików klas w czasie wykonywania .

Opiszmy to.

W JVM każda klasa jest ładowana przez jakąś instancję java.lang.ClassLoader. Za każdym razem, gdy nowa maszyna JVM jest uruchamiana przez zwykłą java <classname>komendę uruchamiającą program Java , pierwszym krokiem jest załadowanie wszystkich klas kluczy do pamięci wymaganych do prawidłowego działania takich java.lang.Objectklas jak i innych klas wykonawczych ( rt.jar).

Obecnie ClassLoader składa się z 3 części:

  • BootstrapClassLoaderJest odpowiedzialny za realizację tych klas dostępne tj ładowania tych klas w pamięci.

  • Kolejnym zadaniem jest załadowanie do pamięci zewnętrznych bibliotek / plików JAR w celu poprawnego działania aplikacji. Za ExtClassLoaderto zadanie odpowiada. Ten program ładujący klasy jest odpowiedzialny za ładowanie wszystkich plików .jar wymienionych w ścieżce java.ext.dirs.

  • Trzecim i głównym ważnym programem ładującym klasy jest AppClassLoader. Program ładujący klasy aplikacji jest odpowiedzialny za ładowanie plików klas wymienionych we właściwości systemowej java.class.path.

Należy również zauważyć, że domyślne implementacje ClassLoader mogą zostać zastąpione, co umożliwia dostosowanie maszyny JVM w użyteczny i interesujący sposób, co pozwala całkowicie przedefiniować sposób wprowadzania plików klas do systemu.

wprowadź opis obrazu tutaj

Sprawdź to, aby dowiedzieć się więcej o module ładującym klasy Java .

Jasio
źródło