playframework1‎ > ‎controller‎ > ‎

インタセプタの優先順序を指定する

Url Redirector Modified

@After, @Before, @Finally, @Catch
といったアノテーションを使うと、アクション処理、テンプレート処理の間に、アノテーションを付けたメソッドが実行される。

タイミングは下記のとおり。

@Before → action → @After → template → @Finally

@Catch はactionメソッドで例外が発生すると実行される。
影響範囲はコントロールクラス内だが、記述したクラスを継承したり、@With でクラス指定されることにより、別のコントロールクラス内の処理でも呼び出される。

疑問

同じコントロールクラス内に同種のインタセプタが複数あった場合、どのような順序で実行されるのだろうか。
以下のようなコードを記述し、実行してみた。
public class Application extends Controller {
     @Before
     public static void before1() {    Logger.info("before1");        }
    
     @Before
     public static void before2() {    Logger.info("before2");        }
    
     @Before
     public static void before3() {    Logger.info("before3");        }
    
     public static void index() {
         Logger.info("action method.");
         render();
     }

     @After
     public static void after1() {      Logger.info("after1");        }
    
     @After
     public static void after2() {      Logger.info("after2");        }

     @After
     public static void after3() {      Logger.info("after3");        }
}

実行結果

14:11:06,590 INFO  ~ before2
14:11:06,591 INFO  ~ before3
14:11:06,591 INFO  ~ before1
14:11:06,591 INFO  ~ action
14:11:06,627 INFO  ~ after2
14:11:06,627 INFO  ~ after1
14:11:06,627 INFO  ~ after3

名前順かと思いきや、不定?
どうやって順序を決めているのだろうか。

その前に、アノテーションを付けた処理を実行している箇所を特定。
play.mvc.ActionInvoker.invoke(Request, Response)

どうやらアノテーションの引数に priority と言うのがあり、小さい値ほど早く実行されるようだ。
デフォルトが0になっている。

すべて同じ値だと、順番はJavaの実装に依存するようだ。
play.utils.JavaWithCaching.findAllAnnotatedMethods(Class<?>)で取得した結果を、Collections.sort()で並べ替え。比較はpriorityという仕様。

あれ、@Withはどうやって実現しているの?と調べてみると、findAllAnnotatedMethods内で実現していた。

アノテーションの探し順。
  1. 自身クラス内から候補を探す。
  2. 自クラスに@Withがあれば、そのクラスを探しにいく(そのクラスを基準にfinAllAnnotatedMehtodsを実行)
  3. 継承元のクラスへ。1番へ戻る。
なので、自クラス内が最優先。自クラスに@With指定があれば、指定されたクラスから探す。

自クラスの継承元クラスへ遡り、再び探す。
継承を遡るほど、後で追加される。

以上はフレームワーク内部の実装であるので、今後も不変とは限らない。なので、この動きを期待すべきではない。

結論

順序を定義したいのなら、priorityを設定し、優先順を明示すべき。

ちなみに @Util を付けると、actionメソッドの対象から除外される。
public static void で、action以外のメソッドを作ったときに付与する。