-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の実行例を調べてみます。
- Before Advice[1: Navigator] - "Ah! Cat on the way!"
- Before Advice[2: ABS] - "Ooops, danger!"
- Core Concern[HandlingCar] - "Turn right!"
- After Advice[2: ABS] - "kikikiki..."
- 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のスタックを抜けます。