注:「ブリッジ」、「変換」、「バインディング」などの次の単語は、基本的に同じ概念です。
log4j-over-slf4jおよびslf4j-log4j12は、Javaログシステムに関連する2つのJARパッケージです。 ClassPathの下に同時に表示されると、スタックオーバーフローの例外を引き起こす可能性があります。例外情報はほぼ次のとおりです(SLF4Jの公式ウェブサイトドキュメントから抜粋されたLog4J-over-slf4j.jarとslf4j-log4j12.jarの両方がクラスパスで、Stackoverflowerrorを先取りします):
スレッド「Main」Java.lang.StackoverFlowerrorの例外
java.util.hashtable.containskey(hashtable.java:306)
atorg.apache.log4j.log4jloggerfactory.getLogger(log4jloggerfactory.java:36)
atorg.apache.log4j.logmanager.getlogger(logmanager.java:39)
atorg.slf4j.impl.log4jloggerfactory.getLogger(log4jloggerFactory.java:73)
atorg.slf4j.loggeractory.getlogger(loggerfactory.java:249)
atorg.apache.log4j.category。<init>(category.java:53)
atorg.apache.log4j.logger .. <init>(logger.java:35)
atorg.apache.log4j.log4jloggerfactory.getLogger(log4jloggerFactory.java:39)
atorg.apache.log4j.logmanager.getlogger(logmanager.java:39)
atorg.slf4j.impl.log4jloggerfactory.getLogger(log4jloggerFactory.java:73)
atorg.slf4j.loggeractory.getlogger(loggerfactory.java:249)
at org.apache.log4j.category .. <init>(category.java:53)
atorg.apache.log4j.logger .. <init>(logger.java:35)
atorg.apache.log4j.log4jloggerfactory.getLogger(log4jloggerFactory.java:39)
atorg.apache.log4j.logmanager.getlogger(logmanager.java:39)
後続の行は省略しています...
既存のロギングシステム
この例外の特定の理由を分析する前に、既存のJavaロギングシステムをすばやく理解する必要があります。次の図は、既存のJavaロギングシステムの図です。
上記の写真はあまり正確ではありませんが、既存のJavaログシステムの主要な構造を明確に表示できます。 Javaロギングシステムは、ログファサードインターフェイス、ブリッジ、およびログフレームワーク固有の実装の3つの部分にほぼ分割できます。
Javaロギングフレームワークには多くの種類があります。最も簡単なのはJava自身のJava.util.loggingであり、最も古典的なものはlog4jです。その後、LOG4Jよりも優れたパフォーマンスを備えたログバックが表示されるため、他のログフレームワークはあまり一般的に使用されていません。アプリケーションがこれらの特定のログフレームワークのAPIを使用してログ出力要件を満たすことは確かに可能ですが、通常、各ログフレームワーク間のAPIは互換性がないため、アプリケーションはログフレームワークを置き換える柔軟性を失います。
特定のログフレームワークAPIを直接使用するよりも合理的なオプションは、ログファサードインターフェイスを使用することです。ログファサードインターフェイスは、特定のログフレームワークに依存しないAPIのセットを提供します。アプリケーションは、JDBCに似たこれらの独立したAPIを使用することにより、特定のログフレームワークから切り離すことができます。最古のログファサードインターフェイスはコモンズログでしたが、現在最も人気のあるものはSLF4Jです。
ログファサードインターフェイス自体には、通常、実際のログ出力機能がありません。下部の特定のログフレームワークAPIを呼び出す必要があります。つまり、実際には特定のログフレームワークと組み合わせて使用する必要があります。多くの特定のログフレームワークがあり、ほとんど互いに互換性がないため、ログファサードインターフェイスが任意のログフレームワークと組み合わされている場合、JDBCとさまざまな異なるデータベースの組み合わせに対応するJDBCドライバーが必要なように、対応するブリッジが必要になる場合があります。
前述のように、上記の写真は正確ではなく、これは単なる主要な部分であり、実際の状況は必ずしも「ログファサードインターフェイス - >ブリッジ - >ログフレームワーク」の単純な一方向ではないことに注意してください。実際、独立したブリッジは不要であることがあり、ログファサードAPIを特定のログフレームワークAPIに変換するのは橋だけではありません。ログフレームワークAPIをログファサードAPIに変換するブリッジもあります。
率直に言って、いわゆる「ブリッジ」は、特定のAPIセットの擬似実装にすぎません。この実装は、APIで宣言された関数を直接完了するわけではなく、同様の関数を持つ他のAPIを呼び出します。これにより、「APIのセット」から「他のAPI」への移行が完了します。 A-to-B.JarとB-to-A.Jarの2つのブリッジがある場合、アプリケーションがAまたはBのAPIを呼び出し始めると何が起こるか想像できます。これは、最初に導入されたスタックオーバーフロー例外の基本原理です。
SLF4J転送バインディング
上記は、既存のJavaロギングシステムの一般的な説明にすぎないため、問題を詳細に説明することはできません。 SLF4Jと特定のログフレームワークの間の架橋状況をさらに理解する必要があります。
SLF4Jは、特定のログフレームにブリッジします
次の画像は、展開時間にログフレームワークを使用したSLF4Jの公式Webサイトドキュメントのドキュメントの拘束力からのものです。
SLF4Jが特定のログフレームワークと組み合わせるための多くのソリューションがあることがわかります。もちろん、各溶液の最上層(緑色のアプリケーション層)は統合されています。それらは、SLF4J(Light Blue Abstract APIレイヤー)によって提供されるAPIを直接呼び出し、SLF4J-API.jarに依存しています。次に、SLF4J APIを下向きに行うと、非常に無料になり、ほとんどすべての特定のロギングフレームワークを使用できます。図の2番目のレイヤーは水色であることに注意してください。左下の隅の凡例を見ると、これは抽象ログAPIを表していることがわかります。つまり、具体的な実装ではありません。下層が左側の最初のソリューションのような特定のログフレームワークの実装と組み合わされていない場合、ログは出力できません(デフォルトで標準出力に出力されるかどうかはわかりません)。
写真の3番目のレイヤーは、特定のログフレームワークがここで関与し始めているため、明らかに第1層と2番目のレイヤーほどきれいではありません。
まず、3階の中央にある2つのレイクブルーブロックを見てみましょう。これは、アダプターレイヤー、つまりブリッジです。左側のslf4j-log4j12.jarブリッジは、名前に基づいてslf4jからlog4jへのブリッジであることがわかります。同様に、右側のslf4j-jdk14.jarは、slf4jによってJavaネイティブログに実装されたブリッジです。それらの次のレイヤーは、対応するログフレームワークの実装です。 log4jの実装コードはlog4j.jarであり、7月の実装コードは既にJVMランタイムに含まれており、個別のJARパッケージは必要ありません。
3階の残りの3つのダークブルーブロックを見てみましょう。それらの3つは特定のロギングフレームワークの実装でもありますが、SLF4J APIを直接実装するため、ブリッジは必要ありません。言うまでもなく、slf4j-simple.jarおよびslf4j-nop.jar、1つはslf4jの単純な実装であり、もう1つはslf4jの空の実装であることがわかりますが、通常はあまり役に立ちません。 LogBackがSLF4J APIを実装する理由は、Log4Jの著者でもあるLogbackとSlf4Jが同じ人物であるためです。
3番目のレイヤーのすべての灰色の瓶パッケージには赤いボックスがあります。つまり、それらはすべてSLF4J APIを直接実装しています。ただし、レイクブルーブリッジによるSLF4J APIの実装は、ログを直接出力するのではなく、他のログフレームワークのAPIを呼び出します。
その他のログフレームワークAPIは、slf4jに呼び戻します
SFL4Jから他のログフレームワークまで上記の橋のみが存在する場合、問題がない場合があります。しかし、実際には、関数が上記の反対である別のタイプのブリッジがあり、他のログフレームワークのAPIをSLF4J APIに変換します。次の写真は、SLF4Jの公式ウェブサイトドキュメントブリッジレガシーAPIからのものです。
上記の図は、これまでに他のログフレームワークAPIからSLF4Jに安全にコールバックできる3つのケースすべてを示しています。
左上隅の最初のケースを例として取ります。基礎となるSLF4Jがログバックフレームワークに架かるとき、上層がSLF4Jに戻ることを可能にするログフレームワークAPIがLog4JとJulを含みます。 JCLはロギングフレームワークの特定の実装ではありませんが、そのAPIはSLF4Jに呼び戻すことができます。コンバージョンを実装するための方法は、元のログフレーム瓶を図にリストした特定のブリッジジャーに置き換えることです。 Logbackは元々SLF4J APIの実装であるため、SLF4J APIへのログバックAPIにはログバックAPIの変換が含まれていないことに注意してください。
3つの状況を読んだ後、JCL APIを含む他のログフレームワークのほぼすべてのAPIが自由にSLF4Jにリダイレクトできることがわかります。しかし、SLF4Jに呼び戻すログフレームワークが、SLF4Jが現在ブリッジングしているログフレームワークと同じではないという制限があります。この制限は、A-to-B.jarとB-to-A.Jarが同時にクラスパスに現れるのを防ぐことであり、AとBは常に再帰的に互いに呼び出し、最後にオーバーフローを積み重ねることになります。現在、この制限はテクノロジーによって保証されていませんが、開発者自身によってのみ保証されています。これが、SLF4Jの公式Webサイトが、すべての合理的な方法が上記の3つの状況にのみあることを強調している理由です。
この時点で、最初に示されている例外の原則は基本的に明確でした。さらに、上記の図から、log4j-over-slf4jとslf4j-log4j12だけでなく、例外と同様の組み合わせがあることがわかります。 SLF4Jの公式ウェブサイトは、JCL-Over-SLF4J.JarとSLF4J-JCL.JARの別のペアも指摘しました。
コードの例
以前の分析は理論的です。 LOG4J-Over-SLF4JとSLF4J-LOG4J12が実際のコードで同時に使用されている場合でも、例外が必ずしも発生しない場合があります。次のコードは、slf4jのAPIを呼び出してログを出力し、slf4jはlog4jにブリッジされます。
パッケージテスト; public class helloworld {public static void main(string [] args){org.apache.log4j.basicconfigurator.configure(); org.slf4j.logger = org.slf4j.loggerfactory.getlogger(helloworld.class.class.class);JARパッケージを構成するようにclassPathを構成します(log4jはlog4j-over-slf4jの前にあることに注意してください):
この場合、テストプログラムを実行すると、ログを正常に出力でき、スタックオーバーフロー例外はありません。ただし、クラスパスのjar注文を調整する場合:
テストプログラムを再度実行すると、この記事の初期スタックオーバーフローと同様のスタックオーバーフロー例外が発生します。あなたは明らかな定期的な繰り返しを見ることができます:
シーケンスチャート分析
上記の写真は、スタックオーバーフローの詳細なコールプログラム列図です。呼び出し1から1.1、1.1.1を呼び出します...最後に、1.1.1.1.1(図の最後の呼び出し)に達すると、それは1とまったく同じであることがわかります。したがって、後続のプロセスは完全に繰り返されます。
最初のヒューズは、図に示されているLoggerFactory.getLogger()だけではないことに注意してください。アプリケーションには、スタックオーバーフローの例外をトリガーできる他のいくつかの直接コールがあります。たとえば、前の例コードでは、最初のステートメントorg.apache.log4j.basicconfigurator.configure()は、実際には最初のステートメントorg.apache.log4j.basicconfigurator.configure()ですが、その後の相互無限の再帰コールプロセスは基本的に以前の図と同じです。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。