Maison  >  Article  >  Java  >  Compréhension approfondie des chargeurs Java

Compréhension approfondie des chargeurs Java

王林
王林avant
2019-11-29 13:44:292468parcourir

Compréhension approfondie des chargeurs Java

1. Classes et chargeurs de classes

Chargeur de classes : La première étape de la phase de chargement, via le nom complet d'une classe. chargez le flux d'octets binaires de cette classe dans le jvm.

Classes et chargeurs de classes : le caractère unique de toute classe est déterminé par elle-même et par le chargeur de classe qui la charge. Le fait que deux classes soient égales dépend du principe qu'elles sont chargées par le même chargeur de classe.

La machine virtuelle JVM comprend deux chargeurs de classe : l'un est le chargeur de classe de démarrage (Bootstrap ClassLoader), qui est implémenté en C++ ; l'autre est tous les autres chargeurs de classe implémentés en Java.

Du point de vue d'un programme Java :

1) Démarrez le chargeur de classes : responsable du chargement des classes dans le répertoire lib ou dans le chemin spécifié par le paramètre -Xbootclasspath. , le nom du fichier est obligatoire. Il est reconnu par la machine virtuelle. S'il n'est pas reconnu par la jvm, il ne peut pas être chargé.

2) Chargeur de classe d'extension : responsable du chargement de toutes les bibliothèques de classes dans le répertoire libexit ou dans le chemin spécifié par la variable système java.exit.dirs.

3) Chargeur de classe d'application (chargeur de classe système) : C'est la valeur de retour de la méthode getSystemClassloader() dans Classloader. Responsable du chargement de la bibliothèque de classes spécifiée sur le chemin de classe utilisateur S'il n'y a pas de chargeur de classe personnalisé dans l'application, ce sera le chargeur de classe par défaut dans le programme.

Enseignement vidéo en ligne gratuit : Tutoriel vidéo Java

Modèle de délégation parentale

Compréhension approfondie des chargeurs Java

À l'exception du chargeur de classe de démarrage de niveau supérieur, tous les autres chargeurs de classe ont leur propre chargeur de classe parent. La relation parent-enfant n'est pas implémentée par héritage, mais par une relation de combinaison pour réutiliser le chargeur de classe parent.

Processus de travail : le chargeur de classe reçoit la demande de chargement de classe –> délègue la demande au chargeur de classe parent (jusqu'à ce que le chargeur de classe de niveau supérieur soit démarré) –> l'échec de chargement est renvoyé au chargeur de classe enfant –> Le chargeur de sous-classe tente de charger

Avantages du modèle de délégation parent : assurer la stabilité de l'API Java sous-jacente et éviter de charger des classes personnalisées avec le même nom (Object ) comme classe de base, ce qui entraîne de multiples différences de classe (objet) portant le même nom, provoquant une confusion dans le comportement de base de Java.

Code source du modèle de délégation parentale :

La méthode ajoute un verrou de synchronisation pour garantir la sécurité des threads. Vérifiez d'abord si la classe a été chargée. Sinon, appelez le parent. chargeur de classe. méthode loadClass(), si le chargeur de classe parent est vide, cela signifie le chargeur de classe de démarrage, alors le chargeur de classe de démarrage est appelé.

Si la classe parent ne parvient pas à se charger, une ClassNotFoundException sera levée, puis appellera votre propre méthode findClass() pour la charger.

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    //同步锁
    synchronized (getClassLoadingLock(name)) {
        // 首先检车这个类是不是已被加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    //如果父类不为空则调用父类加载器的loadClass方法
                    c = parent.loadClass(name, false);
                } else {
                    //没有父类则默认调用启动类加载器加载
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                //如果父类加载器找不到这个类则抛出ClassNotFoundException
            }


            if (c == null) {
                // 父类加载器失败时调用自身的findClass方法加载
                long t1 = System.nanoTime();
                c = findClass(name);


                //记录
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

3. Destruction du modèle de délégation parentale

1 La première destruction du

modèle de délégation parentale est apparue. dans JDK1 Après 2, alors que le chargeur de classe et la classe abstraite java.lang.ClassLoader existaient déjà.

Par conséquent, pour des raisons de compatibilité ascendante, une nouvelle méthode protégée findClass a été ajoutée à ClassLoader après JDK1.2. Les utilisateurs écrivent leur propre logique de chargement de classe dans la méthode findClass au lieu de remplacer la méthode loadClass pour garantir que le chargement de classe personnalisé est conforme au modèle de délégation parent.

2. La deuxième destruction

Le modèle lui-même est défectueux. La délégation parentale peut assurer l'unification des classes de base de chaque chargeur de classe. C'est à ce moment-là que le code utilisateur appelle la classe de base. Elle ne s'applique pas si la classe de base rappelle le code utilisateur. Par exemple, dans les scénarios impliquant SPI, chargez le code SPI requis.

Pour une introduction au mécanisme SPI, veuillez vous référer à d'autres articles.

Afin de résoudre ce problème, le chargeur de contexte de thread (Thread Context ClassLoader) est introduit. Ce chargeur de classe peut être défini via la méthode setContextClassLoader() dans la classe java.lang.Thread. non créé lorsque Le paramètre sera hérité du thread parent. S'il n'y en a pas globalement, la valeur par défaut est le chargeur de classe d'application. Ce chargeur peut être utilisé pour terminer l'action du chargeur de classe parent demandant au chargeur de classe enfant de se charger.

3. Le troisième dommage

est causé par la poursuite de la dynamique du programme, telle que le déploiement à chaud, le remplacement à chaud, etc.

Par exemple, la norme modulaire OSGi R4.2 modifie la structure arborescente de la délégation parentale en une structure de réseau plus complexe.

Tutoriels d'articles Java recommandés : Tutoriel d'introduction à Java

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer