Préface
Tout le monde doit savoir que lorsqu'un projet Java est démarré, le JVM trouvera la méthode principale et chargera le fichier de classe et le fichier de classe dans le package JAR référencé en fonction des appels entre les objets (les étapes sont divisées en chargement, vérification, préparation, analyse, initialisation, utilisation et déchargement). La zone de méthode ouvre la mémoire pour stocker la structure de données d'exécution de la classe (y compris les variables statiques, les méthodes statiques, les pools constants, les structures de classe, etc.), et en même temps, l'objet de classe correspondant est généré dans le tas pour pointer de la structure de données d'exécution de la classe correspondante dans la zone de méthode.
Pour résumer dans la phrase la plus simple, le processus de chargement des classes est que le JVM lit le fichier bytecode de classe via des flux IO en fonction du chemin d'accès du fichier de classe requis et l'injecte en mémoire via une série d'étapes d'analyse et d'initialisation. Les chargeurs de classe dans Java incluent: BootstrapClassloader (couche supérieure), ExtClassloader, AppClassloader et Classloader définis par l'utilisateur (couche inférieure). Pour différents types de packages JAR (ou fichiers de classe), JVM aura différents types de chargeurs de classe à charger.
La relation correspondante est la suivante:
BootstrapClassloader est utilisé pour charger les classes requises pour l'exécution de JVM:
Java_home / jre / lib / ressources.jar: java_home / jre / lib / rt.jar: java_home / jre / lib / sunrasign.jar: java_home / jre / lib / jsse.jar: java_home / jre / lib / jce.jar: java_home / jre Java_home / jre / lib / jfr.jar: java_home / jre / lib / classes
ExtClassloader est utilisé pour charger des classes d'extension:
../Java/extensions: ../java_home/jre/lib/ext: ../library/java/extensions:/network/library/java/extensions: ../system/library/java/extensions: ../lib/java
AppClassloader est utilisé pour charger les classes créées sous ClassPath et les classes référencées dans le package JAR dans notre projet.
L'ensemble du chargement de classe est chargé par un mécanisme appelé délégation parent.
Par exemple, une classe est chargée par le chargeur de niveau le plus bas (Classloadher définis par l'utilisateur). Ce chargeur appellera d'abord le chargeur de niveau précédent (AppClassloader) pour le chargement, et l'AppClassloader continuera à être remis au niveau supérieur (ExtClassloader) pour le chargement jusqu'au bootstrapClassloadher. Si le ClassPath chargé par BootstrapClassloader ne peut pas trouver cette classe, il sera remis au chargeur (ExtClassloader) de la couche suivante pour le chargement. Si cette classe ne peut être trouvée, elle continuera d'être remise à la couche suivante (appclassloader) pour le chargement. Et ainsi de suite, si le chargeur de classe défini par l'utilisateur ne peut pas trouver cette classe, le programme lancera un classNotFoundError.
L'ensemble du processus de chargement est affiché comme suit:
(L'image est citée sur: https://www.cnblogs.com/xing901022/p/4574961.html)
Le suivi du code source de la source de chargement de classe est le suivant (le code source a été simplifié de manière appropriée ici). Les lecteurs peuvent cliquer sur le code source pour afficher:
Package java.lang.classloader; Import ...... Class protégé <?> LoadClass (nom de chaîne, boolean résolve) lance classNotFoundException {synchronisé (getClassloadingLock (name)) {// Tout d'abord, trouver dans la mémoire de la machine virtuelle si cette classe a été chargée ... le problème principal avec les mensonges de cache de classe! ! ! Classe <?> C = findloadClass (name); if (c == null) {long t0 = System.NanoTime (); essayez {if (parent! = null) {// Laissez le chargeur de couche précédent charger d'abord c = parent.loadClass (name, false); } else {c = findbootstrapClassorNull (name); }} catch (classNotFoundException e) {// classnotfoundException lancé si classe n'est pas trouvée // à partir du chargeur de classe parent non null} if (c == null) {// Calendar la méthode findClass implémentée par ce chargeur pour charger c = findClass (name); }} if (résolve) {résolveclass (c); } return c; }}Vous pouvez pleinement apprécier le processus de mécanisme de délégation des parents dans le code source, et les trois phrases de code les plus importantes ont été marquées:
Si l'utilisateur a besoin d'un chargeur personnalisé et de charger le fichier de classe du chemin spécifié, il doit hériter du Classloader et implémenter la méthode FindClass (nom de chaîne). Par exemple:
package com.linuxidc.utils; import java.io.bytearrayoutputStream; import java.io.fileInputStream; import java.io.ioException; import java.io.inputStream; public class ServiceClassloader étend classloader {private string classpath; public ServiceClassloader (String ClassPath) {this.classPath = classPath; } / ** * Réécrivez la méthode FindClass de la classe parent. La CLASSE de la classe Parent appellera cette méthode * / @Override Protected Class <?> FindClass (String Name) lève ClassNotFoundException {class <?> C = null; octet [] classData = getClassData (name); if (classData! = null) {c = définieclass (name, classData, 0, classData.length); } else {lancer une nouvelle classe NotFoundException (); } return c; } // Lisez le fichier de classe via le flux IO et convertissez-le en un byte privé de byte [] getClassData (String name) {String path = classPath + "/" + name.replace ('.', '/') + ".Class"; InputStream isttream = null; ByteArrayOutputStream byteArrayOutputStream = new bytearrayoutputStream (); try {isttream = new FileInputStream (path); octet [] tampon = nouveau octet [1024]; int temp = 0; while ((temp = isttream.read (tampon))! = - 1) {bytearrayoutputStream.write (tampon, 0, temp); } if (bytearrayoutputStream! = null) {return bytearrayoutputStream.toByteArray (); }} catch (exception e) {e.printStackTrace (); } enfin {try {if (isttream! = null) {isttream.close (); }} catch (ioException e) {e.printStackTrace (); } try {if (bytearrayoutputStream! = null) {bytearrayoutputStream.close (); }} catch (ioException e) {e.printStackTrace (); }} return null; }}Le code pour l'utilisation du chargeur de classe est le suivant:
ServiceClassloadher ServiceClassloadher = new ServiceClassloadher ("c: / myClass"); czlass <?> C = ServiceClassLoader.loadClass ("com.linuxidc.service.myclass");Si vous utilisez le même objet ServiceClassloader pour charger le même fichier de classe plusieurs fois, l'objet de classe après chaque charge est le même! Cependant, si une nouvelle classe personnalisée différente charge le même fichier de classe, un objet de classe différent sera renvoyé à chaque fois.
Remarque: Le fichier de classe que vous souhaitez charger ne peut pas être placé dans le répertoire de ClassPath et toutes les sous-répertoires, sinon elle sera chargée d'abord par l'AppClassloader (ceci est parce que le chargement de classe adopte le mécanisme de délégation parent, et le chargeur AppClass peut charger tous les fichiers de classe sous le ClassPath). À chaque fois, le même appclassloader est chargé, il y aura donc des problèmes de mise en cache de classe.
Cela résout le problème de l'utilisation directe de la réflexion lorsque la classe JVM charge.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.