インタセプタを定義するもうひとつのやり方は、別のクラスにインタセプタメソッドを置き、@Interceptor
タグで対象Beanクラスにアノテーションを付けることです。次のコードは、対象Beanオブジェクトの全メソッド呼び出しの呼び出しトレースと実行時間をログ出力するインタセプタクラスです。インタセプタ内のctx.proceed()
は次のインタセプタと対象メソッドを再帰的に呼び出すことを思い出してください。なので、finally
内のコードは、対象メソッドと下流のインタセプタがすべて返った後に呼ばれます。
public class Tracer {
@AroundInvoke
public Object log (InvocationContext ctx)
throws Exception {
String className = ctx.getBean().getClass().getName();
String methodName = ctx.getMethod().getName();
String target = className + "." + methodName + "()";
long start = System.currentTimeMillis();
System.out.println ("Invoking " + target);
try {
return ctx.proceed();
} catch(Exception e) {
throw e;
} finally {
System.out.println("Exiting " + target);
cal.setTrace(cal.getTrace() + "
" +
"Exiting " + target);
long time = System.currentTimeMillis() - start;
System.out.println("This method takes " +
time + "ms to execute");
}
}
}
次はBeanクラスの@Interceptor
アノテーションです。
@Stateful
@Interceptors (Tracer.class)
public class InterceptorCalculator implements Calculator, Serializable {
// ... ...
}
@Interceptors
アノテーションを使って、Beanに複数のインタセプタクラスを指定することもできます。それらのインタセプタはアノテーションの属性配列に現れる順に呼び出されます。Beanクラス内のインタセプタメソッドは最後に呼び出されます。