minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

例外発生時にJoin Pointを設定する

handler キーワードを使います。

pointcut errorFunc() : handler(Exception);
before() : errorFunc() {
    System.out.println("exception!");
}

この場合、Exception(もしくはそのサブクラス)が発生した箇所が
Join Pointとして定義されます。
このように、Join Pointは動的に定義することも可能です。

変数をバインドする

上の例では、どんな例外が発生したのかという肝心な情報が抜け落ちています。
これを解決するには、メソッドの引数にException型の変数を追加する必要があります。
それには、args キーワードを使います。

pointcut errorFunc(Exception e) : handler(Exception) && args(e);
before(Exception e) : errorFunc(e) {
    System.out.println("exception! - " + e.getMessage());
}

発生した例外オブジェクトが、AspectJロジック実行時に
パラメータとして渡されます。

メソッドを置き換える

アスペクト指向の本領発揮といった機能がこれです。
例えば「標準出力への出力を全てログに出力する」機能を作ることが出来ます。
ただし、この機能は完全ではありません(理由は後述)。

Logger logger = Logger.getLogger(this.getClass());
pointcut sysout(String s) :
    call(void java.io.PrintStream.println(..)) && args(s);
void around(String s) : sysout(s) {
    logger.debug("[STDOUT] " + s);
}

順に説明します。

sysout(String s)

Pointcut「sysout」を定義します。
引数sは後にバインドする必要があります。

call(void java.io.PrintStream.println(..))

PrintStream.println メソッド呼び出しをJoin Pointに設定します。

&& args(s)

引数が一つのメソッドだけを対象とします。
Pointcutの定義文により、sはString型になります。

void around(String s) : sysout(s) { ... }

Join Pointのコードを置き換えるロジックを定義します。

以上により、PrintStream.println(String) メソッドの呼び出し箇所を置き換えます。

logger.debug("[STDOUT] " + s);

標準出力に出力しようとしていた内容を、ログに出力します。
これにより、標準出力には何も出力されなくなります。

完全でない理由

始めに説明したように、この機能は完全ではありません。
PrintStreamクラスは標準出力以外にも使われるので
このままでは標準出力への出力以外のものまでログに出力される危険性があります。