Logger.getLogger(MyClass.class)は、log4jロガーを初期化する最良の方法ですか?


13

このMkyongチュートリアルでは、ロガーを次のように初期化することを提案しています。

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

今、おそらくあなたが使用する他のすべてのクラスには、ロガーがあり、同じようにロガーを初期化します。

私の質問は-これはそれを行うための最良の方法ですか?それは...繰り返しのようです。


2
これについて何が冗長だと思いますか(Javaの構文を脇に置きます)?。ロガーを保持する変数を作成し、getLogger()取得するロガーの名前を通知する必要があります。
kdgregory 2015年

2
@kdgregory私がすべてのクラスで同じことをしているという事実。
dwjohnston 2015年


3
移行するには古すぎますが、この質問はここではトピックから外れており、StackOverflowに適しています。
アンドレスF.

1
@AndresF。技術的な問題というよりは、コードスタイル/デザインパターンについての質問の方が多いので、ここに置いておきます。
dwjohnston 2016

回答:


16

あなたのコメントは、「冗長」はすべてのクラスでこのコード行を繰り返す必要性を指すと述べています。私の最初の応答は、全体像で、すべてのクラスに2行のコード(変数定義とインポートステートメント)を追加することはそれほど大きな問題ではないということです。特に、振る舞いを持ち、したがってロギングを行う必要があるクラスにそれらを追加する必要があるだけです。とはいえ、使用している特定のコード行では、コピーアンドペーストエラーが発生する傾向があります(これについては後で詳しく説明します)。

ただし、代替手段が必要なため、以下にいくつか示します。理由は、それらを使用する場合と使用しない場合があります。

アプリ全体に単一のロガーを使用する

どのクラスがレポートしているのかを気にしない場合、または必要なすべてのコンテキストをメッセージに入れても構わない場合は、単純なシングルトンロガーが機能します。

LoggerSingleton.getInstance().debug("MyController is running")

私の意見では、ロギングフレームワークの大きな利点の1つは、ログメッセージを別の宛先に送信する場合のみ、別のロガーインスタンスによってコンテキストが提供されることです。1行のコードを保存するためだけにそれをあきらめることはしません(まだインポートが必要です)。

さらに、これにより、使用する時点での冗長性が向上し、キーストロークがはるかに多くなります。

使用時にロガーを作成する

変数を削除するという理由だけで、これを捨てています。私はそれにコメントする必要はないと思います。それはロガーインスタンスを取得するための私の好ましいテクニックを示していますが。

Logger.getLogger(getClass()).debug("blah blah blah");

Beanポストプロセッサを使用してロガーを挿入する

例ではSpringを使用しており、Springを使用すると、Bean初期化コードにフックできます。loggerメンバー変数のBeanを検査し、Logger見つかったときにインスタンスを作成するポストプロセッサーを作成できます。

このようなポストプロセッサは数十行のコードにすぎませんが、これはアプリケーションのもう1つの重要な部分であり、そのためバグの別の潜在的な原因となります。私はそれらをできるだけ少なくすることを好みます。

ミックスインを使用する

ScalaとGroovyは、動作をカプセル化できる特性を提供します。典型的なScalaパターンは、Loggingトレイトを作成し、ロギングが必要なクラスに追加することです。

class MyController with Logging

残念ながら、これは言語を切り替える必要があることを意味します。Java 8を使用していない限りLogging、「デフォルトのメソッド」でインターフェースを作成できます。

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

今、あなたのクラスコード内で、あなたは単に使うことができます

getLogger().debug("blah blah blah");

これは簡単ですが、いくつかの欠点があります。1つには、すべてのインターフェイスメソッドがパブリックであるため、それを使用するすべてのクラスのインターフェイスを汚染します。特にインターフェース/実装の分離に従う場合は、Springによってインスタンス化および注入されるクラスにのみ使用する場合は、おそらくそれほど悪くはありません。

より大きな問題は、すべての呼び出しで実際のロガーインスタンスを検索する必要があることです。高速ですが不要です。

そして、まだimportステートメントが必要です。

ロガーをスーパークラスに移動する

繰り返します。繰り返しロガー定義が冗長になることはありませんが、そうであれば、これを排除するための最良のアプローチだと思います。

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

これで、コントローラークラスはから継承されAbstractControllerlogger変数にアクセスできます。@Controller具象クラスに注釈を付ける必要があることに注意してください。

一部の人々はこれを継承の倒錯だと思うでしょう。私は、クラスAbstractControllerではなくクラスに名前を付けることで、それらを軟化させようとしましたAbstractProjectClassis-a関係があるかどうかを自分で決めることができます。

他の人々は、静的変数ではなくインスタンス変数の使用に反対します。IMO静的ロガーは、クラス名を明示的に参照する必要があるため、コピーアンドペーストエラーが発生しやすくなります。getClass()ロガーが常に正しいことを確認します。


継承クラスのgetClass()には注意する必要があると思います。MethodHandles.lookup()。lookupClass()はjdk 7以降でより優れています
yuxh

@luxh-説明はありますか?
kdgregory

ここをチェックしてください:stackoverflow.com/a/6653577/4652536
yuxh

@yuxh-その質問でのMethodHandlesの唯一の言及(リンクした回答には含まれていませんでした)は、同様のサポートされていないアサーションであり、説明を求めるコメントが付いています。あなたは持っています権威アサーションのサポートMethodHandles.lookup().lookupClass()よりも優れているのObject.getClass()
kdgregory

MethodHandles.lookup().lookupClass()静的変数のために使用することができ、エラーをコピー&ペーストする傾向がなく、高速で:stackoverflow.com/a/47112323/898747はそれがあるので、私は非常に静的バイン私のロガーのようにそれは余分のInportを意味しているのが、最も価値がaの:)
FableBlaze

0

@kdgregoryによって提供される回答を拡張するために、Groovyは、クラスでAST変換を実行するアノテーションとして@Slf4jgroovy.util.logging.Slf4j)をそのまま提供し、log指定されていない場合はデフォルトで変数名を想定するロガーでそれを処理します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.