11

私は、多くのトレース ログを作成するポリシーを持つ会社のコードベースで作業してきました。したがって、ほとんどすべてのメソッドには、次のように始まるコードがあります。

String LOG_METHOD = "nameOfMethod(String,List<Long>):void";
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params)); 
}

そして、次のように終了します(finally-clause またはメソッドの最後で:

if(logger.isTraceEnabled()) { 
    logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD)); 
}

実際にはもっと多くのコードがありますが、これが基本的な考え方です。CompanyMessagesこれはコードを乱雑にし、他のコーダーは、監視ツールが読み取るメッセージをフォーマットするために必要な特定のクラスを使用しない独自の解釈で常に混乱させています。したがって、上記のすべての@LogBefore('logLevel')コードを削除し、 &のような注釈を使用してトレース ログを必要とするすべてのメソッドを提供する方法を探してい@LogAfter('logLevel')ます。

私がこのソリューションを選択した理由は、他の開発者が新しいことを学ぶ必要がなく、コードの代わりに注釈を使用できるようにするためです。私は、何百もの Web アプリケーションと何十人もの開発者を展開するサーバー環境で働いています。そのため、余分なコーディングや大規模なライブラリを追加せずに、これを Web アプリケーションに実装する方法を探していました。これは、私が提案したものと同様のアノテーションを使用し、各 Web アプリケーションで簡単に構成できる、小さくて安定した AOP 実装を探していることを意味します。パフォーマンスも重要です。これを AOP で実装する最も簡単な例は何ですか?

編集:探しているものと非常によく似たものを見つけましたが、これにはいくつかの問題があります。ロギングが必要なすべてのクラスを構成する必要があります。これは、注釈を使用するだけでなく、より多くのリソースを消費します。スプリング構成はそれ<aop:aspectj-autoproxy/>を修正しますか?

4

3 に答える 3

5

注釈と AOP ポイントはどちらも有効です。注釈を使用して、ロギングについて AOP フレームワークに警告します。

私がするもう1つのことは、ロガーを修正することです。

あなたが持っている:

String LOG_METHOD = "nameOfMethod(String,List<Long>):void"
if(logger.isTraceEnabled()) { 
    Object[] params = new Object[] { string, list };
    logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params) ); 
}

代わりに、次のようなものを検討してください。

logger.trace(this, LOG_METHOD, string, list);

次のように実装できます。

public void trace(Object obj, Object args...) {
    if (parentLogger.isTraceEnabled()) {
        logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args);
    }
}

ロギング ユーティリティのほとんどは、Java で可変引数を使用する前に作成されたものです。

また、有効になっていないときにログの呼び出しを防止するガードも必要ですが、その主な動機は、過去のほとんどの人があなたがしたこと、またはさらに悪いことをしたからです。

logger.trace("My message: " + string + " with list " + list);

トレースが有効かどうかに関係なく、高価な式があります。

しかし、varargs を活用することで、両方を取得できます。MessageFormat のようなものを使用するだけで(おそらくすでに行っているでしょう)、簡単に取得できます:

logger.trace("My message: {0} with list {1}", string, list);

トレースが無効になっている場合、これは 3 つのポインターを渡す安価なメソッド呼び出しです。したがって、それを保護してコードを乱雑にする動機ははるかに少なくなります。

最新のロガーのほとんどは適切にオーバーライドしないため、通常は単純に拡張するのではなく、カプセル化する必要があります。

問題を直接解決するわけではなく、トレース情報を動的に生成します。しかし、これは、既存のコード ベースを簡単かつ段階的にクリーンアップする単純な妥協点です。

また、他に 2 つのオプションがあります。

1 つは、コードを実行し、まだ存在しない場所にログインを追加するポスト プロセッサを使用することです。これにより、手動で入力する負担が軽減されますが、コードが乱雑になります (まだどこにでも存在するため)。

2 つ目は、コンパイル時に注釈プロセッサを使用することです。これはより洗練されています。しかし、それはコンパイル中に実行され、コンパイル時に情報を使用してクラスを実行および拡張します。良い点は、コードがクリーンであることです (おそらく注釈を保存してください) だけでなく、すべての作業はコンパイル時に行われます。オブジェクトファクトリの派手なクラスローダーではなく、ランタイムへの影響はありません。ビルドしたら、プロセッサを捨てることができます。実行時にはまったく必要ありません。

これを活用するプロジェクトがありますが、その名前は私にはわかりません。コンパイル時にセッター/ゲッターをコードに自動的に追加します。私はそれについて良いことを聞いたことがあります。

AOP フレームワークは、コンパイル時にこれを行う可能性があります。私はそれらに精通しているとは言えませんが、いずれにせよ、この手法は調査する価値があります。

ただし、少なくとも、ロガーをラップします。これは漸進的で安全であり、コードを徐々にクリーンアップし、一般的に注釈が機能しない可能性がある場合にログを記録するのに役立ちます。

于 2011-04-09T16:28:56.057 に答える
3

注釈が解決策だったとは思いません。クラスまたはインスタンスに注釈を付けるということは、実行時にクラスに追加情報を与えることを意味し、それ自体は何もしません。アノテーションを使用してクラスを処理し、実行時にそれらのアノテーションに基づいて各メソッドの前後にコードを追加するコードが必要になります。

したがって、注釈を追加して準備を整える方法はありません。クラスはメソッドのログを開始します。

解決策は AOP である必要があります。これはまさに、AOP が最初に発明された問題です。各メソッドでクラス/メソッド/アクションを定義すると、問題が解決されます。

まあ、おそらく、実行時に注釈とクラスの変更を使用して動作させることができますが、最終的には自作の AOP になります :-)

于 2011-04-09T12:33:48.683 に答える