Remarque: Les mots suivants tels que "pont", "conversion" et "liaison" sont fondamentalement le même concept.
log4j-over-slf4j et slf4j-log4j12 sont deux packages en pot liés au système de journal Java. Lorsqu'ils apparaissent sous le chemin de classe en même temps, ils peuvent provoquer des exceptions de débordement de pile. Les informations d'exception sont à peu près les suivantes (extrait du document de site Web officiel SLF4J détecté à la fois log4j-over-slf4j.jar et slf4j-log4j12.jar sur le chemin de classe, prématurant StackOverflowerror):
Exception dans Thread "Main" java.lang.stackoverflowerror
sur java.util.hashtable.containskey (hashTable.java:306)
sur org.apache.log4j.log4jloggerfactory.getlogger (log4jloggerfactory.java:36)
sur org.apache.log4j.logmanager.getlogger (logManager.java:39)
à org.slf4j.impl.log4jloggerfactory.getlogger (log4jloggerfactory.java:73)
sur org.slf4j.loggerfactory.getlogger (loggerfactory.java:249)
sur org.apache.log4j.category. <init> (catégorie.java:53)
sur org.apache.log4j.logger .. <init> (logger.java:35)
sur org.apache.log4j.log4jloggerfactory.getlogger (log4jloggerfactory.java:39)
sur org.apache.log4j.logmanager.getlogger (logManager.java:39)
à org.slf4j.impl.log4jloggerfactory.getlogger (log4jloggerfactory.java:73)
sur org.slf4j.loggerfactory.getlogger (loggerfactory.java:249)
sur org.apache.log4j.category .. <init> (catégorie.java:53)
sur org.apache.log4j.logger .. <init> (logger.java:35)
sur org.apache.log4j.log4jloggerfactory.getlogger (log4jloggerfactory.java:39)
sur org.apache.log4j.logmanager.getlogger (logManager.java:39)
les lignes suivantes omises ...
Système d'exploitation existante
Avant d'analyser les raisons spécifiques de cette exception, il est nécessaire de comprendre rapidement le système de journalisation Java existant. Le chiffre suivant est un diagramme du système de journalisation Java existant:
L'image ci-dessus n'est pas très précise, mais elle peut clairement afficher la structure principale du système de journal Java existant. Le système de journalisation Java peut être à peu près divisé en trois parties: l'interface de la façade de journal, le pont et la mise en œuvre du cadre de journal.
Il existe de nombreux types de cadres de journalisation Java. Le plus simple est le propre java.util.util de Java, et le plus classique est log4j. Plus tard, une connexion avec de meilleures performances que Log4j est apparue, de sorte que les autres cadres journaux ne sont pas très couramment utilisés. Il est certainement possible que les applications utilisent directement les API de ces cadres de journal spécifiques pour répondre aux exigences de sortie du journal, mais comme les API entre chaque cadre journal sont généralement incompatibles, cela fait perdre l'application la flexibilité du remplacement du cadre journal.
Une option plus raisonnable que l'utilisation directe de l'API de trame de journal spécifique consiste à utiliser l'interface de façade de journal. L'interface de façade de journal fournit un ensemble d'API indépendant de cadres journaux spécifiques. Les applications peuvent se découpler à partir de cadres journaux spécifiques en utilisant ces API indépendantes, qui est similaire à JDBC. La première interface de façade en journal était les communes, mais la plus populaire à l'heure actuelle est SLF4J.
L'interface de façade de journal elle-même n'a généralement pas la capacité de sortie du journal réelle. Il doit encore appeler l'API spécifique du cadre du journal en bas, c'est-à-dire qu'il doit en fait être utilisé en combinaison avec le cadre journal spécifique. Étant donné qu'il existe de nombreux cadres de journal spécifiques et sont principalement incompatibles les uns avec les autres, si l'interface de façade de journal est combinée avec n'importe quel cadre journal, il peut nécessiter un pont correspondant, tout comme la combinaison entre JDBC et diverses bases de données différentes nécessite un pilote JDBC correspondant.
Il convient de noter que, comme mentionné précédemment, l'image ci-dessus n'est pas exacte, ce n'est que la partie principale, et la situation réelle n'est pas toujours une simple ligne à sens unique de "Interface de façade de journal-> Bridge-> Framework log". En fait, les ponts indépendants ne sont parfois pas nécessaires, et ce n'est pas seulement un pont qui convertit l'API de façade en journal en une API journalière spécifique. Il existe également des ponts qui convertissent l'API Log Framework en API de façade de journal.
Pour le dire franchement, le soi-disant "pont" n'est rien de plus qu'une pseudo implémentation d'un certain ensemble d'API. Cette implémentation ne complète pas directement les fonctions déclarées par l'API, mais appelle d'autres API avec des fonctions similaires. Cela complète la transition d'un "ensemble d'API" à "d'autres API". S'il y a deux ponts, A à B.jar et B-to-A.jar, vous pouvez imaginer ce qui se passera lorsque l'application commencera à appeler l'API de A ou B. Il s'agit du principe de base de l'exception de débordement de pile qui a été introduite pour la première fois.
liaison de transfert SLF4J
Ce qui précède n'est qu'une explication générale du système de journalisation Java existant, et il n'est pas possible d'expliquer le problème en détail. Nous devons davantage comprendre la situation de pontage entre SLF4J et le cadre journal spécifique.
ponts SLF4J à un cadre de journal spécifique
L'image suivante provient de la liaison du document de site Web officiel du SLF4J avec un cadre de journalisation au moment du déploiement:
Vous pouvez voir qu'il existe de nombreuses solutions pour SLF4J pour combiner avec des cadres journaux spécifiques. Bien sûr, la couche supérieure (couche d'application verte) de chaque solution est unifiée. Ils appellent directement l'API fournis par SLF4J (couche API abstraite bleu clair) et s'appuient sur SLF4J-API.JAR. Ensuite, si vous faites l'API SLF4J vers le bas, il sera très gratuit et vous pouvez utiliser presque tous les cadres de journalisation spécifiques. Notez que la deuxième couche de la figure est bleu clair. En regardant la légende dans le coin inférieur gauche, nous pouvons voir que cela représente l'API logarithmique abstraite, ce qui signifie qu'ils ne sont pas des implémentations concrets. Si la couche inférieure n'est pas combinée avec une implémentation de trame de journal spécifique comme la première solution à gauche, le journal ne peut pas être sorti ( il n'est pas sûr qu'il puisse être sorti à la sortie standard par défaut ).
La troisième couche de l'image n'est évidemment pas aussi soignée que les première et deuxième couches, car le cadre journal spécifique a commencé à être impliqué ici.
Tout d'abord, regardons les deux blocs bleus du lac au milieu du troisième étage, qui sont la couche d'adaptateur, c'est-à-dire le pont. Le pont SLF4J-LOG4J12.Jar à gauche peut indiquer qu'il s'agit d'un pont de SLF4J à Log4J basé sur le nom. De même, le slf4j-jdk14.jar à droite est un pont implémenté par SLF4J aux journaux natifs de Java. La couche suivante d'entre eux est l'implémentation du cadre journal correspondant. Le code d'implémentation de Log4j est log4j.jar, et le code d'implémentation Jul est déjà inclus dans le runtime JVM et ne nécessite pas de package JAR distinct.
Regardons les trois blocs bleu foncé restants au troisième étage. Les trois d'entre eux sont également des implémentations de cadre de journalisation spécifiques, mais ils ne nécessitent pas de ponts car ils implémentent eux-mêmes directement l'API SLF4J. Inutile de dire que Slf4J-Simple.jar et Slf4j-nop.jar, vous pouvez dire que l'un est une simple implémentation de SLF4J et l'autre est une implémentation vide de SLF4J, ce qui n'est pas très utile à des temps normaux. La raison pour laquelle Logback implémente également l'API SLF4J est considérée comme parce que Logback et SLF4J sont de la même personne, qui est également l'auteur de Log4J.
Tous les packages en pot gris dans la troisième couche ont des boîtes rouges, ce qui signifie qu'ils implémentent tous directement l'API SLF4J. Cependant, la mise en œuvre de l'API SLF4J par le Lake Blue Bridge ne publie pas directement des journaux, mais appelle plutôt l'API des autres cadres de journal.
API d'autres framework journal rappelle à SLF4J
Si seuls les ponts ci-dessus de SFL4J à d'autres cadres journaux existent, il n'y a peut-être aucun problème. Mais en fait, il existe un autre type de pont, dont les fonctions sont exactement l'opposé de ce qui précède, ils convertissent l'API d'autres cadres journaux en API SLF4J. L'image suivante provient de la SLF4J API Héritage du site officiel du site officiel du site Web:
La figure ci-dessus montre les trois cas qui peuvent se rappeler en toute sécurité sur SLF4J à partir d'autres API du cadre journal jusqu'à présent.
Prenant le premier cas dans le coin supérieur gauche comme exemple, lorsque le SLF4J sous-jacent est pontée dans le cadre de journal de bord, les API du cadre du journal qui permettent à la couche supérieure de remonter à SLF4J incluent Log4j et Jul. Bien que JCL ne soit pas une implémentation spécifique d'un cadre de journalisation, son API peut toujours être rappelée à SLF4J. Pour implémenter la conversion, la méthode consiste à remplacer le pot de trame de journal d'origine par un pot de pont spécifique répertorié sur la figure. Il convient de noter que l'API de journalisation de l'API SLF4J n'inclut pas la conversion de l'API de journalisation, car la journalisation est à l'origine une implémentation de l'API SLF4J.
Après avoir lu les trois situations, vous constaterez que presque toutes les API des autres cadres journaux, y compris l'API JCL, peuvent être redirigées vers SLF4J à volonté. Mais il y a une seule limitation que le cadre journal qui rappelle à SLF4J ne peut pas être le même que le cadre journal que SLF4J se pose actuellement. Cette limitation vise à empêcher A à B.Jar et B-to-A.jar d'apparaître dans le chemin de classe en même temps, ce qui a permis à A et B de s'appeler constamment de manière récursive, et enfin de chouchouter. À l'heure actuelle, cette restriction n'est pas garantie par la technologie, mais uniquement par le développeur eux-mêmes. C'est pourquoi le site officiel de SLF4J souligne que toutes les méthodes raisonnables ne sont que dans les trois situations de l'image ci-dessus.
À ce stade, le principe de l'exception montrée au début a été essentiellement clair. De plus, à partir de la figure ci-dessus, nous pouvons voir qu'il peut y avoir des combinaisons similaires aux exceptions non seulement log4j-over-slf4j et slf4j-log4j12. Le site officiel de SLF4J a également souligné une autre paire: jcl-over-slf4j.jar et slf4j-jcl.jar.
Exemple de code
L'analyse précédente est théorique. Même si log4j-over-slf4j et slf4j-log4j12 sont utilisés en même temps dans le code réel, les exceptions ne peuvent pas nécessairement se produire. Le code suivant appelle l'API de SLF4J pour sortir le journal, et SLF4J est pontée sur Log4J:
Test de package; classe publique Helloworld {public static void main (String [] args) {org.apache.log4j.basicconfigurator.configure (); org.slf4j.logger logger = org.slf4j.loggerfactory.getlogger (helloworld.class); logger.info ("bonjour");Configurez le CLASSPATH pour configurer le package JAR (Notez que Log4j est avant log4j-over-slf4j):
Dans ce cas, l'exécution du programme de test peut sortir le journal normalement et il n'y aura pas d'exception de débordement de pile. Mais si vous ajustez l'ordre de pot sur le chemin de classe pour:
L'exécution du programme de test entraînera une exception de débordement de pile similaire au débordement de pile initial dans cet article. Vous pouvez voir des répétitions périodiques évidentes:
Analyse des graphiques de séquence
L'image ci-dessus est un diagramme de colonne de programme d'appel détaillé du débordement de pile. À partir de l'appel 1, appelez 1.1, 1.1.1 ... Enfin, lorsqu'il atteint le 1.1.1.1.1 (le dernier appel de la figure), il est constaté qu'il est exactement la même que 1, de sorte que le processus ultérieur est complètement répété.
Il convient de noter que le fusible initial n'est pas seulement LoggerFactory.getLogger () illustré sur la figure. Il existe plusieurs autres appels directs dans l'application qui peuvent déclencher des exceptions de débordement de pile. Par exemple, dans l'exemple de code précédent, la première instruction org.apache.log4j.basicconfigurator.configure () est en fait la première instruction org.apache.log4j.basicconfigurator.configure (), mais le processus d'appel récursif mutuel mutuel ultérieur est essentiellement la même figure.
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.