Każda klasa użyje własnego modułu ładującego klasy, aby załadować inne klasy. Więc jeśli ClassA.class
referencje ClassB.class
następnie ClassB
musi być na ścieżce klasy classloader z ClassA
, lub jego rodziców.
Moduł ładujący klasy kontekstu wątku jest bieżącym modułem ładującym klasy dla bieżącego wątku. Obiekt można utworzyć z klasy w, ClassLoaderC
a następnie przekazać do wątku należącego do ClassLoaderD
. W takim przypadku obiekt musi użyć Thread.currentThread().getContextClassLoader()
bezpośrednio, jeśli chce załadować zasoby, które nie są dostępne w jego własnym module ładującym.
ClassB
musi to być ścieżka klasy programuClassA
ładującego (lubClassA
rodziców programu ładującego)? Czy nie jest możliwe, abyClassA
moduł ładujący nadpisałloadClass()
, tak że można go pomyślnie załadować,ClassB
nawet jeśliClassB
nie ma ścieżki klas?ClassA.class
referencjeClassB.class
”?To nie odpowiada na pierwotne pytanie, ale ponieważ pytanie jest wysoko ocenione i powiązane z każdym
ContextClassLoader
zapytaniem, myślę, że ważne jest, aby odpowiedzieć na powiązane pytanie, kiedy należy użyć modułu ładującego klasy kontekstu. Krótka odpowiedź: nigdy nie używaj modułu ładującego klasy kontekstu ! Ale ustaw tęgetClass().getClassLoader()
opcję, gdy trzeba wywołać metodę, w której brakujeClassLoader
parametru.Gdy kod z jednej klasy prosi o załadowanie innej klasy, właściwym modułem ładującym jest ten sam moduł ładujący co klasa wywołująca (tj
getClass().getClassLoader()
.). W ten sposób działa 99,9% czasu, ponieważ JVM robi to samo przy pierwszym utworzeniu instancji nowej klasy, wywołaniu metody statycznej lub uzyskaniu dostępu do pola statycznego.Jeśli chcesz utworzyć klasę za pomocą odbicia (na przykład podczas deserializacji lub ładowania konfigurowalnej nazwanej klasy), biblioteka wykonująca odbicie powinna zawsze pytać aplikację, który moduł ładujący klasy ma użyć, otrzymując
ClassLoader
jako parametr od aplikacji. Aplikacja (która zna wszystkie klasy wymagające budowy) powinna ją przekazaćgetClass().getClassLoader()
.Każdy inny sposób uzyskania modułu ładującego klasy jest niepoprawny. Jeśli biblioteka używa hacków takich jak
Thread.getContextClassLoader()
,sun.misc.VM.latestUserDefinedLoader()
lubsun.reflect.Reflection.getCallerClass()
jest to błąd spowodowany brakiem interfejsu API. ZasadniczoThread.getContextClassLoader()
istnieje tylko dlatego, że ktokolwiek zaprojektowałObjectInputStream
API, zapomniał zaakceptować tenClassLoader
parametr, a ten błąd nawiedził społeczność Java do dziś.To powiedziawszy, wiele wielu klas JDK używa jednego z kilku hacków, aby odgadnąć jakiś moduł ładujący klasy. Niektóre używają
ContextClassLoader
(co kończy się niepowodzeniem, gdy uruchamiasz różne aplikacje we współużytkowanej puli wątków lub gdy opuszczaszContextClassLoader null
), niektóre chodzą po stosie (co kończy się niepowodzeniem, gdy bezpośredni obiekt wywołujący klasę jest biblioteką), niektóre używają modułu ładującego klasy systemowe (co jest w porządku, pod warunkiem, że jest udokumentowane, aby używać tylko klas wCLASSPATH
module ładującym) lub w programie ładującym klasy bootstrap, a niektóre używają nieprzewidywalnej kombinacji powyższych technik (co tylko bardziej komplikuje sprawę). Spowodowało to dużo płaczu i zgrzytania zębami.Korzystając z takiego interfejsu API, najpierw spróbuj znaleźć przeciążenie metody, która akceptuje moduł ładujący klasę jako parametr . Jeśli nie ma rozsądnej metody, spróbuj ustawić
ContextClassLoader
przed wywołaniem interfejsu API (i zresetować go później):źródło
Istnieje artykuł na javaworld.com, który wyjaśnia różnicę => Którego ClassLoadera należy użyć
(1)
(2) z tego samego źródła:
źródło
bootstrap
moduł ładujący klasy nadrzędnej jest ustawiony jako moduł ładujący klasy kontekstowej, alesystem
moduł ładujący klasy potomnej, któryThread
jest konfigurowany. TeJNDI
zajęcia są następnie upewniając się, aby użyćThread.currentThread().getContextClassLoader()
, aby załadować klasy implementacji JNDI dostępne na ścieżce klasy.Dodając do odpowiedzi @David Roussel, klasy mogą być ładowane przez wiele programów ładujących klasy.
Pozwala zrozumieć, jak działa moduł ładujący klasy .
Z bloga javina Paula w javarevisited:
ClassLoader
przestrzega trzech zasad.Zasada delegowania
Bootstrap ClassLoader jest odpowiedzialny za ładowanie standardowych plików klas JDK z rt.jar i jest nadrzędny dla wszystkich programów ładujących klasy w Javie. Moduł ładujący klasy bootstrap nie ma żadnych rodziców.
Rozszerzenie ClassLoader przekazuje żądanie załadowania klasy do swojego rodzica, Bootstrap, a jeśli się nie powiedzie, ładuje klasę z katalogu jre / lib / ext lub dowolnego innego katalogu wskazanego przez właściwość systemową java.ext.dirs
Moduł ładujący klasy systemu lub aplikacji i jest odpowiedzialny za ładowanie klas aplikacji z zmiennej środowiskowej CLASSPATH, opcji -classpath lub -cp, atrybutu Class-Path pliku manifestu w pliku JAR.
Moduł ładujący klasy aplikacji jest dzieckiem rozszerzenia ClassLoader i jest implementowany przez
sun.misc.Launcher$AppClassLoader
klasę.UWAGA: Z wyjątkiem modułu ładującego klasy Bootstrap , który jest implementowany w języku ojczystym głównie w języku C, wszystkie moduły ładujące klasy Java są implementowane za pomocą
java.lang.ClassLoader
.Zasada widoczności
Zasada wyjątkowości
źródło