Préface
Pour une analyse du principe de démarrage de Spring Boot lui-même, veuillez vous référer à: http://www.vevb.com/article/141478.htm
La relation d'héritage Classloader dans Spring Boot peut exécuter la démo fournie ci-dessous et l'exécuter dans différents scénarios. Vous pouvez connaître la relation successive de Classloader des applications de démarrage de Spring dans différents scénarios.
https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-classloader-contex
Il y a trois situations:
Dans l'IDE, la fonction principale Run exécute directement le Classloader de Spring est directement SystemClassloader. Les URL de Classloader contiennent tous les pots et leurs propres cibles / classes
========= URL Classloader de l'application de démarrage de Spring URL ==============
Classloader URL: Sun.Misc.Launcher$AppCLASSOLODER@2A139A55
file: / users / hengyunabc / code / java / spring-boot-inside / démo-classloader-context / cible / classes /
fichier: /users/hengyunabc/.m2/repository/org/springframework/cloud/spring-cloud-starter/1.1.9.release/spring-cloud-starter-1.1.9.release.jar
fichier: /users/hengyunabc/.m2/repository/org/springframework/boot/spring-boot-starter/1.4.7.release/spring-boot-starter-1.4.7.release.jar
...
Courir en tant que gros pot
Mvn Clean Packagejava -jar Target / Demo-Classloader-Context-0.0.1-Snapshot.jar
Le Classloader qui exécute la fonction principale de l'application est lancéedUrlClassLoader, et son parent est SystemClassloader.
========== Classloader Tree ==============.
org.springframework.boot.loader.launchedUrlclassloader@1218025c
- Sun.Misc.Launcher$AppCLASSOLODER@6BC7C054
- Sun.Misc.Launcher$ExtClassLoader@85ede7b
Et LaunchedURLClassLoader的urls sont BOOT-INF/classes!/ Répertoire dans fat jar et tous les pots du boot-inf / lib.
========= URL Classloader de l'application de démarrage de Spring URL ==============
Classloader URL: org.springframework.boot.loader.launchedUrlclassloader@1218025c
jar: file: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloadher-context-0.0.1-snapshot.jar! / boot-inf / classes! /
jar: fichier: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar! /boot-inf/lib/spring-boot-1.4.7.release.jar! /
jar: fichier: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar! /boot-inf/lib/spring-web-4.9.9.release.jar! /
...
Les URL de SystemClassLoader sont demo-classloader-context-0.0.1-SNAPSHOT.jar lui-même.
========== URL de chargeur de classe système ==============
URL de Classloader: Sun.Misc.Launcher$AppCLASSOLODER@6BC7C054
fichier: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-snapshot.jar
Exécuter comme le répertoire décompressé
MVN Clean PackageCD TargetUnzip Demo-Classloader-Context-0.0.1-Snapshot.jar -d DemoCd Demojava Org.SpringFramework.boot.Loadher.PropertiesLauncher
Le Classloader qui exécute la fonction principale de l'application est LaunchedURLClassLoader , et son parent est SystemClassLoader .
========== Classloader Tree ==============.
org.springframework.boot.loader.launchedUrlclassloader@4aa298b7
- Sun.Misc.launcher$AppCLASSOLODER@2A139A55
- Sun.Misc.Launcher$ExtClassloadher@1b6d3586
Les URL du LaunchedURLClassLoader sont les packages JAR ci-dessous BOOT-INF/classes/ et /BOOT-INF/lib/ dans le répertoire de décompression.
========= URL Classloader de l'application de démarrage de Spring URL ==============
Classloader URL: org.springframework.boot.loader.launchedUrlclassLoader@4aa298b7
file: / users / hengyunabc / code / java / spring-boot-inside / démo-classloader-context / cible / démo / boot-inf / classes /
Jar: fichier: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/lib/bcpkix-jdk15on-1.55.jar! /
Jar: fichier: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/lib/bcprov-jdk15on-1.55.jar! /
jar: fichier: /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/lib/classmate-1.3.3.jar! /
Les URL de SystemClassLoader ont uniquement le répertoire actuel:
========== URL de chargeur de classe système ==============
Classloader URL: Sun.Misc.Launcher$AppCLASSOLODER@2A139A55
file: / users / hengyunabc / code / java / spring-boot-inside / démo-classloader-context / cible / démo /
En fait, il existe deux autres façons de courir: mvn spring-boot:run et mvn spring-boot:run -Dfork=true , mais il est rarement utilisé et ne sera pas discuté séparément. Si vous vous sentez intéressé, vous pouvez vous lancer par vous-même.
Résumé de la relation successive de Classloader dans Spring Boot
Lorsque la fonction principale est exécutée dans l'IDE, il n'y a qu'un seul Classloader, c'est-à-dire, SystemClassloader
Lorsqu'il fonctionne en tant que gros pot, il y a un lancé
Les URL de LankeDeDurlClassloadher sont les pots sous Boot-Inf / Classes et Boot-Inf / Lib dans Fat Jars. Les URL de SystemClassloader sont elles-mêmes de gros pots.
Lors de l'exécution du répertoire dézippé, il est similaire à Fat Jar, mais l'URL est sous la forme d'un répertoire. Le format d'annuaire aura une meilleure compatibilité.
Spring Boot Versions 1.3. et 1.4.
Dans Spring Boot 1.3. * Version
La classe de chargeur de démarrage à ressort est placée dans le pot de gros
Les modifications de la structure d'emballage de Spring Boot 1.4 ont été introduites par cet engagement
https://github.com/spring-projects/spring-boot/commit/87fe0b2adeef85c842c009bfeebac1c84af8a5d7
L'intention d'origine de cet engagement est de simplifier la relation d'héritage du Classloader, d'implémenter le LaunsedUrlClassloader d'une manière intuitive des parents-premier, et en même temps, la structure d'emballage est plus proche de l'application de package de guerre traditionnelle.
Cependant, ce changement a causé de nombreux problèmes complexes. D'après ce qui précède, nous avons analysé la relation d'hérédité de Classloader un peu étouffée.
Certains impacts de la relation de succession de classe actuelle
De nombreux utilisateurs peuvent constater qu'un code fonctionne bien dans l'IDE mais ne fonctionne pas lorsqu'il est réellement déployé. Plusieurs fois, il est causé par la structure de Classloader. Voici quelques cas.
Demo.jar! / Boot-Inf / Classes! / De cette façon, l'URL ne fonctionne pas
Parce que Spring Boot étend le protocole JAR standard, lui permettant de prendre en charge le pot multicouche en pot et répertoire en pot. Reportez-vous à l'analyse du principe de démarrage de l'application Spring Boot
Bien qu'il y aura un pot dans Jar dans Spring Boot 1.3, un code relativement robuste peut gérer cette situation, comme TomCat8 lui-même prend en charge JAR dans JAR.
Cependant, la plupart du code ne prendra pas en charge plusieurs URL tels que demo.jar!/BOOT-INF/classes!/ , Donc dans Spring boot1.4, de nombreux codes de bibliothèque seront invalides.
Problèmes de ressources sous Demo.jar! / Meta-Inf / Ressources
Dans la spécification Servlet 3.0, les applications peuvent placer des ressources statiques sous Meta-Inf / Ressources, et le conteneur servlet soutiendra la lecture. Mais à partir des résultats de l'héritage ci-dessus, nous pouvons trouver un problème:
Cela crée des phénomènes étranges:
En outre, l'exemple officiel de la botte de Spring ne prend en charge que le format d'emballage de la guerre et ne prend pas en charge Fat Jar, qui est également causé par cela.
Problèmes avec la valeur de retour de GetResource ("") et GetResources ("")
La sémantique de GetResource ("") doit renvoyer la première URL des URL de Classloader. Plusieurs fois, les utilisateurs pensent qu'il s'agit de leur propre répertoire de classe ou de l'URL de JAR.
Mais en fait, parce que Classloader charge la liste des URL, il est aléatoire, qui est lié à l'implémentation de bas niveau du système d'exploitation, et il ne peut garantir que l'ordre des URL est le même. Par conséquent, le résultat renvoyé par GetResource ("") est souvent différent.
Cependant, de nombreuses bibliothèques ou applications reposent sur ce code pour localiser les ressources de numérisation, afin qu'elles ne fonctionnent pas sous Spring Boot.
De plus, il convient de noter que Spring Boot s'exécute sous trois formes différentes, et les résultats renvoyés par GetResources ("") sont également différents. Les utilisateurs peuvent modifier le code dans la démo par eux-mêmes et imprimer les résultats.
En bref, ne comptez pas sur ces deux API, il est préférable de placer une ressource pour la localiser vous-même. Ou utilisez directement le mécanisme de balayage des ressources fourni par Spring lui-même.
Problème de classification sauvage similaire à ClassPath *: ** - Service.xml
L'utilisateur a plusieurs modules de code et plusieurs fichiers de configuration de printemps * -service.xml sont placés sous différents modules.
Si un utilisateur utilise des caractères génériques comme ClassPath *: ** - Service.xml pour charger des ressources, il est très probable qu'il puisse se charger correctement lors de l'exécution dans l'IDE, mais il ne peut pas se charger sous le pot de gros.
Vous pouvez voir l'analyse pertinente de la propre documentation de Spring:
https://docs.spring.io/spring/docs/4.3.9.release/javadoc-api/org/springframework/core/io/support/pathmatchingresourcepatternresolver.html
AVERTISSEMENT: Notez que «ClassPath:» lorsqu'il est combiné avec des modèles de style fourmi ne fonctionnera que de manière fiable avec au moins un répertoire racine avant le début du modèle, à moins que les fichiers cibles réels ne résident dans le système de fichiers. Cela signifie qu'un modèle comme «CLASSPATH: *. XML» ne récupérera pas les fichiers à partir de la racine des fichiers JAR mais plutôt uniquement à partir de la racine des répertoires élargis. Cela provient d'une limitation de la méthode Classloader.getResources () de JDK qui ne renvoie que les emplacements du système de fichiers pour une chaîne vide passée (indiquant des racines potentielles à rechercher). Cette implémentation ResourcePatternResolver essaie d'atténuer la limitation de la recherche de racine de jar via UrlClassloader Introduction et "java.class.path" manifester l'évaluation; Cependant, sans garantie de portabilité.
C'est-à-dire que lorsque vous utilisez ClassPath * pour correspondre à d'autres packages JAR, il doit y avoir une couche de répertoire à l'avant, sinon cela ne correspondra pas. Ceci est dû à la fonction classloader.getResources ().
Parce que lors de l'exécution de l'IDE, les autres modules dont dépend l'application dépend généralement d'un répertoire de classes, donc il n'y a généralement pas de problème.
Cependant, lors de l'exécution avec un pot de gros, d'autres modules sont emballés sous forme de pot et placés sous Boot-Inf / Lib, de sorte que la distribution sauvage échouera pour le moment.
Résumer
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.