-S12: ブレーキタイミング

用語の説明を行います。AOPの用語として、「Core Concern」と「Crosscutting Concern」という言葉があります。これらはそれぞれ日本語として「本質な関心」「横断的な関心」などと訳されてます。今回の例のCore ConcernはBrakingCarの内容であり、Crosscutting ConcernはABSやNavigatorにコーディングした内容です。一般的にCore Concernは各実装しなければならない事象のうち事象固有の「こと」を言い、Crosscutting Concernは様々な事象に現れる「こと」を言います。BrakingCar固有のことはブレーキを踏むことで、横断的なことはABS(ABS)だったり助手席の人(Navigator)でした。たとえばCore Concernがハンドルを切ることだったら、以下のとおりです。

list12-1. ブレーキを踏まずハンドルを切るHandlingCar.java
package tutorial.org.seasar.console;
public class HandlingCar implements Car {
  public void run() {
    System.out.println("Turn right!");
  }
}
list12-2. Core Concernを変えたcar.xml修正版
<?xml version="1.0" encoding="UTF-8"?>
<components>
  <component class="tutorial.org.seasar.console.HandlingCar">
    <aspect pointcut="run">
      <component class="tutorial.org.seasar.console.Navigator"/>
    </aspect>
    <aspect pointcut="run">
      <component class="tutorial.org.seasar.console.ABS"/>
    </aspect>
  </component>
</components>

結果は以下のとおりです。

Ah! Cat on the way!

Ooops, danger!

Turn right!

kikikiki...

Ouch, I have blown the tongue.

猫を見つけるのも、ABSが音を出すのもBreakingCarの例と一緒ですが、ブレーキではなく急ハンドルで猫を避けています。この"Turn right!"がこの例のCore Concernです。一方で、それ以外の"Ah! Cat on the way!"や"kikikiki..."それぞれがCrosscutting Concernです。このCrosscutting Concernの実装たるNavigatorやABSをAOPの用語で「Advice」と呼びます。Seasar2ではAdviceの実装を行う際に、フレームワークに用意された、org.seasar.framework.aop.AroundAdviceを実装しなければならないため、ABSとNavigatorは、AroundAdviceをimplementsし、そのメソッド定義に従って、invoke(Joinpoint)メソッドを実装していました。
AroundAdvice#invoke(Joinpoint)は、joinpoint.proceed();というコードでCore Concernを呼び出す前後でその「時期」が二つに分かれます。すなわち、joinpoint.proceed();の前を「Before (Advice)」と呼び、後を「After (Advice)」と呼ぶことがあります。ABSではBeforeが"Ooops, danger!"、Afterが"kikikiki..."といった文字列出力時期にあたります。ここでlist12-2の実行例を調べてみます。

  1. Before Advice[1: Navigator] - "Ah! Cat on the way!"
  2. Before Advice[2: ABS] - "Ooops, danger!"
  3. Core Concern[HandlingCar] - "Turn right!"
  4. After Advice[2: ABS] - "kikikiki..."
  5. After Advice[1: Navigator] - "Ouch, I have blown the tongue."

<aspect>エレメントの登場順にしたがって、Navigator-ABSの順にBefore部分を実行し、Core ConcernであるHandlingCar#run()の実行後に、今度は<aspect>エレメントの登場順の逆でABS-NavigatorのAfter部分を実行します。例ではAdviceが二つのみですが、登録が多くなっても同じです。登録順にしたがってAdviceのBefore部分をスタックに積むように実行していき、スタックの頂点でコンポーネントのメソッドを実行してから、登録の逆順でAdviceのAfter部分を実行してAdviceのスタックを抜けます。