Chaque classe utilisera son propre chargeur de classe pour charger d'autres classes. Donc , si les ClassA.class
références ClassB.class
alors ClassB
besoin d' être sur le chemin de classe du classloader ClassA
ou ses parents.
Le chargeur de classe de contexte de thread est le chargeur de classe actuel pour le thread actuel. Un objet peut être créé à partir d'une classe dans ClassLoaderC
, puis passé à un thread appartenant à ClassLoaderD
. Dans ce cas, l'objet doit être utilisé Thread.currentThread().getContextClassLoader()
directement s'il souhaite charger des ressources qui ne sont pas disponibles sur son propre chargeur de classe.
ClassB
doit être sur le chemin de classe duClassA
chargeur (ouClassA
des parents du chargeur)? N'est-il pas possible pourClassA
le chargeur de surchargerloadClass()
, de sorte qu'il puisse se charger avec succèsClassB
même s'ilClassB
n'est pas sur son chemin de classe?ClassA.class
référencesClassB.class
»?Cela ne répond pas à la question d'origine, mais comme la question est hautement classée et liée à toute
ContextClassLoader
requête, je pense qu'il est important de répondre à la question connexe de savoir quand le chargeur de classe de contexte doit être utilisé. Réponse courte: n'utilisez jamais le chargeur de classe de contexte ! Mais définissez-le surgetClass().getClassLoader()
lorsque vous devez appeler une méthode à laquelle il manque unClassLoader
paramètre.Lorsque le code d'une classe demande de charger une autre classe, le chargeur de classe correct à utiliser est le même chargeur de classe que la classe appelante (c.-à
getClass().getClassLoader()
-d.). C'est ainsi que les choses fonctionnent 99,9% du temps car c'est ce que la JVM fait elle-même la première fois que vous construisez une instance d'une nouvelle classe, invoquez une méthode statique ou accédez à un champ statique.Lorsque vous souhaitez créer une classe à l'aide de la réflexion (comme lors de la désérialisation ou du chargement d'une classe nommée configurable), la bibliothèque qui effectue la réflexion doit toujours demander à l'application quel chargeur de classe utiliser, en recevant le
ClassLoader
comme paramètre de l'application. L'application (qui connaît toutes les classes qui ont besoin d'être construites) doit la passergetClass().getClassLoader()
.Toute autre façon d'obtenir un chargeur de classe est incorrecte. Si une bibliothèque utilise des hacks tels que
Thread.getContextClassLoader()
,sun.misc.VM.latestUserDefinedLoader()
ousun.reflect.Reflection.getCallerClass()
s'il s'agit d'un bogue provoqué par une déficience de l'API. Fondamentalement, celaThread.getContextClassLoader()
n'existe que parce que celui qui a conçu l'ObjectInputStream
API a oublié d'accepter leClassLoader
paramètre, et cette erreur a hanté la communauté Java à ce jour.Cela dit, de nombreuses classes JDK utilisent l'un des quelques hacks pour deviner quel chargeur de classe utiliser. Certains utilisent le
ContextClassLoader
(qui échoue lorsque vous exécutez différentes applications sur un pool de threads partagé ou lorsque vous quittez leContextClassLoader null
), certains parcourent la pile (qui échoue lorsque l'appelant direct de la classe est lui-même une bibliothèque), certains utilisent le chargeur de classe système (ce qui est bien, tant qu'il est documenté d'utiliser uniquement des classes dans leCLASSPATH
) ou le chargeur de classe bootstrap, et certains utilisent une combinaison imprévisible des techniques ci-dessus (ce qui ne fait que rendre les choses plus confuses). Cela a entraîné beaucoup de pleurs et de grincements de dents.Lorsque vous utilisez une telle API, essayez d'abord de trouver une surcharge de la méthode qui accepte le chargeur de classe comme paramètre . S'il n'y a pas de méthode sensée, essayez de définir
ContextClassLoader
avant l'appel de l'API (et de le réinitialiser après):la source
Il y a un article sur javaworld.com qui explique la différence => Quel ClassLoader utiliser
(1)
(2) de la même source:
la source
bootstrap
chargeur de classe parent qui est défini en tant que chargeur de classe de contexte, mais lesystem
chargeur de classe de chemin de classe enfant avec lequelThread
est configuré. LesJNDI
classes s'assurent ensuite d'utiliserThread.currentThread().getContextClassLoader()
pour charger les classes d'implémentation JNDI disponibles sur le chemin de classe.En plus de la réponse de @David Roussel, les classes peuvent être chargées par plusieurs chargeurs de classe.
Permet de comprendre le fonctionnement du chargeur de classe .
Du blog javin paul dans javarevisited:
ClassLoader
suit trois principes.Principe de délégation
Bootstrap ClassLoader est responsable du chargement des fichiers de classe JDK standard à partir de rt.jar et il est le parent de tous les chargeurs de classe en Java. Le chargeur de classe Bootstrap n'a pas de parents.
L'extension ClassLoader délègue la demande de chargement de classe à son parent, Bootstrap et en cas d'échec, charge le répertoire jre / lib / ext du formulaire de classe ou tout autre répertoire pointé par la propriété système java.ext.dirs
Chargeur de classe système ou d'application et il est chargé de charger des classes spécifiques à l'application à partir de la variable d'environnement CLASSPATH, de l'option de ligne de commande -classpath ou -cp, de l'attribut Class-Path du fichier Manifest dans JAR.
Le chargeur de classe d'application est un enfant d' Extension ClassLoader et son implémenté par
sun.misc.Launcher$AppClassLoader
classe.REMARQUE: à l' exception du chargeur de classe Bootstrap , qui est implémenté en langage natif principalement en C, tous les chargeurs de classe Java sont implémentés à l'aide de
java.lang.ClassLoader
.Principe de visibilité
Principe d'unicité
la source