4

目的: ビジネス ロジックの実行中に例外が発生するたびに、管理者に電子メールを送信します。

これまで、ターゲットメソッドから例外が発生したときに実行され、問題のない「スローアドバイス」に出くわしました。

これは私にとってはうまくいったかもしれませんが、リクエスト属性と次のページの設定に関して追加の処理を行う必要があります。これらのオブジェクトを静的にすることで、ターゲットクラスのオブジェクトをアドバイス付きで共有するのは良い考えではないと思います。コード シナリオを以下に示します。

try{
   //normal processing
} catch (AuthenticationException ae) {
   ae.printStackTrace();
   req.setAttribute("msg", ae.getMessage());

   //execute advice at this point

   return loginPage;
}

お願いします。アドバイスを実行したいポイントを見て、それに応じて解決策を提案してください。

よろしくお願いします

4

4 に答える 4

2

Spring AOP とは対照的に、完全な AspectJ を避けたいことはわかっています。(ところで、なぜ多くの人がそれを恐れているのだろうかhandler(). ただし、制限が 1 つあります。 orbefore()ではなく、アドバイスでのみ機能します。これは、コンパイラの制限によるものです。例外ハンドラーの JVM バイト コードを見ると、ハンドラー ブロックの終了を検出する方法がないことがわかります。とにかく、コンセプトは元の質問に関連しているので、ここでそれがどのように行われるかを示したいと思います. 小さなドライバー アプリケーションと非常に単純なアスペクトを作成しました。after()around()

import java.util.Random;
import javax.naming.AuthenticationException;

public class Application {
    public static void main(String[] args) {
        Application app = new Application();
        System.out.println(app.foo(1, "two", 3d));
        System.out.println(app.bar("one", 2d, 3));
        System.out.println(app.zot(1d, 2, "three"));
    }

    public String foo(int i, String string, double d) {
        try {
            if (new Random().nextBoolean())
                throw new AuthenticationException("wrong password");
        }
        catch (AuthenticationException e) {
            return "return value from catch block";
        }
        return "normal return value";
    }

    public String bar(String string, double d, int i) {
        try {
            if (new Random().nextBoolean())
                throw new IllegalArgumentException("I don't like your arguments");
        }
        catch (IllegalArgumentException e) {
            return "return value from catch block";
        }
        return "normal return value";
    }

    public String zot(double d, int i, String string) {
        try {
            int n = 2/0;
        }
        catch (Throwable t) {
            return "return value from catch block";
        }
        return "normal return value";
    }
}

ご覧のとおりfoobarca. すべてのケースの 50% ですが、zot常に 0 による除算の例外がスローされます。したがって、出力は実行ごとに異なります。

では、すべての例外が黙って飲み込まれ、ログに記録されない場合、どうすれば何が起こっているのかを知ることができるでしょうか? そのようです:

import java.util.logging.Logger;

public aspect ExceptionLoggingAspect {
    final Logger log = Logger.getLogger(ExceptionLoggingAspect.class.getName());

    before(Throwable t) : handler(Throwable+) && args(t) {
        log.warning(thisJoinPointStaticPart + "  ->  " + t);
    }
}

これは非常にシンプルでエレガントで、アプリケーション全体で機能します。ここにいくつかのテスト出力があります:

Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
WARNING: handler(catch(AuthenticationException))  ->  javax.naming.AuthenticationException: wrong password
return value from catch block
Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
WARNING: handler(catch(IllegalArgumentException))  ->  java.lang.IllegalArgumentException: I don't like your arguments
return value from catch block
Apr 6, 2013 12:15:43 PM ExceptionLoggingAspect ajc$before$ExceptionLoggingAspect$1$3d90b181
WARNING: handler(catch(Throwable))  ->  java.lang.ArithmeticException: / by zero
return value from catch block

thisアドバイスでは、いくつかのプロパティへのアクセスや読み取り/更新など、さらに多くのことができます。

于 2013-04-06T10:30:44.063 に答える
1

OK、Spring in Actionのような参考書を読んだ後、Java コードの任意のポイントでスプリング アドバイスを呼び出す方法がないことがわかりました。Spring in Action book では、ポイント カットをきめ細かく制御するために AspectJ を参照することを推奨しています。

AspectJ の追加を避けるために、他の人を助け、貴重な時間を節約できる次のソリューションに出会いました。

1) 例外が発生した場合にのみアドバイスを呼び出したいメソッドには、Around アドバイスを使用します。私の場合と同様に、例外が発生して catch ブロックから抜けたときに電子メール通知を送信したいと考えています。基本的には、アドバイスを呼び出す前に catch ブロックで何らかの処理を行いたいと考えていました。

2) アラウンド アドバイスを使用すると、対象オブジェクトのメンバー変数をメソッドの引数として読み取ることができます。アドバイスとともに何らかのデータを共有したい場合も、方法の 1 つです。私の場合、メールの件名と本文に関するターゲット オブジェクトの詳細が必要でした。

周りのアドバイスのコード:

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class NotificationAdvice implements AfterReturningAdvice  {
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
            System.out.println(returnValue);
            System.out.println(method.getName());
            System.out.println(args[0]);
            System.out.println(((target)target).flag);
    }
}

このアプローチに関するフィードバックや質問を共有してください。

于 2013-03-19T15:37:25.697 に答える
0

私の知る限り、これにはポイントカット式はありません...

必要なことを行うようにロガーを構成することを検討する必要があります。(スタックトレースをコンソールに出力するのはかなり悪い習慣です) のae.printStackTrace();ようなものに置き換えて、 log4jlogback のSMTPAppender など、ログ ツールのメール送信アペンダーの 1 つを構成します。さらに、構成を簡単にするために、ビジネス専用のロガーを使用することもできます。logger.warn(ae)

ここで本当にアスペクトを使用したい場合は、 afterThrowingアドバイスを使用するために、すべてのビジネス例外が少なくとも 1 つのメソッドをバブルアップすることを期待する必要があると思います。

于 2013-03-18T11:36:20.213 に答える