1. 概要

アプリケーションでSLF4Jを使用すると、コンソールに出力されるクラスパスの複数のバインディングに関する警告メッセージが表示されることがあります。

このチュートリアルでは、このメッセージが表示される理由とその解決方法を理解しようとします。

2. 警告を理解する

まず、警告の例を見てみましょう。

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:.../slf4j-log4j12-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:.../logback-classic-1.1.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]

この警告は、SLF4Jが2つのバインディングを検出したことを示しています。 1つはslf4j-log4j12-1.7.21.jarにあり、もう1つはlogback-classic-1.1.7.jarにあります。

ここで、この警告が表示される理由を理解しましょう。

Simple Logging Facade for Java(SLF4J)は、さまざまなloggingフレームワークの単純なファサードまたは抽象化として機能します。 これにより、デプロイメント時に必要なロギングフレームワークをプラグインできます。

これを実現するために、SLF4Jはクラスパスでバインディング(別名プロバイダー)を探します。 バインディングは基本的に、特定のロギングフレームワークをプラグインするために拡張されることを意図した特定のSLF4Jクラスの実装です。

設計上、SLF4Jは一度に1つのロギングフレームワークにのみバインドします。 したがって、クラスパスに複数のバインディングが存在する場合、警告が発行されます。

ライブラリやフレームワークなどの組み込みコンポーネントは、SLF4Jバインディングへの依存関係を宣言してはならないことに注意してください。 これは、ライブラリがSLF4Jバインディングに対するコンパイル時の依存関係を宣言するときに、そのバインディングをエンドユーザーに課すためです。 明らかに、これはSLF4Jの基本的な目的を否定します。 したがって、slf4j-apiライブラリのみに依存する必要があります。

これは単なる警告であることに注意することも重要です。SLF4Jが複数のバインディングを検出すると、リストから1つのロギングフレームワークを選択してバインドします。 警告の最後の行に示されているように、SLF4Jは、実際のバインディングにorg.slf4j.impl.Log4jLoggerFactoryを使用してLog4jを選択しました。

3. 競合するJARの検索

警告には、検出されたすべてのバインディングの場所が一覧表示されます。 通常、これは、不要なSLF4Jバインディングをプロジェクトに一時的に引き込む悪意のある依存関係を特定するのに十分な情報です。

警告から依存関係を特定できない場合は、dependentency:treeMavenの目標を使用できます。

mvn dependency:tree

これにより、プロジェクトの依存関係ツリーが表示されます。

[INFO] +- org.docx4j:docx4j:jar:3.3.5:compile 
[INFO] |  +- org.slf4j:slf4j-log4j12:jar:1.7.21:compile 
[INFO] |  +- log4j:log4j:jar:1.2.17:compile 
[INFO] +- ch.qos.logback:logback-classic:jar:1.1.7:compile 
[INFO] +- ch.qos.logback:logback-core:jar:1.1.7:compile

アプリケーションへのログインにLogbackを使用しています。 そのため、 logback-classicJARに存在するLogbackバインディングを意図的に追加しました。 しかし、 docx4j 依存関係は、 slf4j-log4j12JARとの別のバインディングも引き込みました。

4. 解像度

問題のある依存関係がわかったので、 slf4j-log4j12JARをdocx4j依存関係から除外する必要があります。

<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j</artifactId>
    <version>${docx4j.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Log4jは使用しないので、それも除外することをお勧めします。

5. 結論

この記事では、SLF4Jによって発行される複数のバインディングに関して頻繁に見られる警告を解決する方法を説明しました。

この記事に付属するソースコードは、GitHubから入手できます。