-S13: ブレーキを踏む時

Seasar2へのAdviceの登録は<aspect>エレメントを用いることを説明しましたが、この<aspect>エレメントは任意属性であるpointcut属性を持ちます。pointcut属性はそのままAOPの用語で「Pointcut」を指定するものです。さて、このPointcutとは何でしょうか。以下まず例を示します。だんだん出力メッセージのストーリー性に無理が生じてきているのはご容赦ください。

list13-1. ポイントカット指定を行うInGarageCar.java
package tutorial.org.seasar.console;
public class InGarageCar implements Car {
  public void init() {
    System.out.println("Shi, shi, go away!");
  }
  public void run() {
    System.out.println("Cat) Nyaaago!");
  }
}

そして、設定XMLです。<initMethod>エレメントは復習です。

list13-2. ポイントカット指定を行っているcar.xml修正版
<?xml version="1.0" encoding="UTF-8"?>
<components>
  <component class="tutorial.org.seasar.console.InGarageCar">
    <initMethod name="init"/>
    <initMethod>out.println('=========')</initMethod>
    <aspect pointcut="init">
      <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!

Shi, shi, go away!

Ouch, I have blown the tongue.

=========

Ooops, danger!

Cat) Nyaaago!

kikikiki...

Pointcutの説明の前に、この例でのテクニックについて説明しなければなりません。list13-2では新しい<initMethod>のテクニックを使ってます。list13-2では<initMethod>エレメントを二つ記述しています。はじめの<initMethod>エレメントはInGarageCarの生成時にInGarageCar#init()メソッドを呼ぶという、すでに解説しているものです。二番目の<initMethod>エレメントはname属性がなく、エレメントボディにSelによるプログラムが行われています。<initMethod>エレメントはname属性の有る無しによって、この二通りに場合わけされた機能が提供されています。
name属性の無い<initMethod>エレメントボディではSelによるメソッド実行を、その式言語仕様の枠内で、行います。例示したout.println('=========')では、Javaで書かれたSystem.out.println("=========");と同じ評価が行われます。すなわち、オブジェクトへの参照変数に続けてJavaのようにメソッド記述を行えば該当するメソッド実行が行われるのです。メソッドの引数が複数の場合「,」で引数を区切るなど、ほとんどJavaの記法と同じです。「out」はあらかじめS2Containerに登録されているコンポーネントで、標準出力です。outはデバッグ・テストにちょっと用いたい場合に便利です。
実行結果を見ると、文字列出力より以下の順番で実行されていることがわかります。

  1. Navigator[Before Advice] "Ah! Cat on the way!"
  2. InGarageCar#init() "Shi, shi, go away!"
  3. Navigator[After Advice ] "Ouch, I have blown the tongue."
  4. initMethodによるSel実行 "========="
  5. ABS [Before Advice] "Ooops, danger!"
  6. InGarageCar#run() "Cat) Nyaaago!"
  7. ABS [After Advice ] "kikikiki..."

はじめのコンポーネント生成時に呼ばれるInGarageCar#init()について、pointcut属性に「init」を記述した<aspect>エレメントが登録したAdviceであるNavigatorが包むように処理を行っているます。また、後のInGarageCar#run()実行時には、pointcut属性に「run」を記述した<aspect>エレメントで登録したABSが包んでいます。
<aspect>エレメントは任意でpointcut属性を持ちます。その値はAdviceが適用される(Core Concernとする)コンポーネントメソッドの名前です。pointcut属性を省略すると、コンポーネントのすべてのメソッドにAdviceが適用されることになります。また、pointcut属性の値は「,」(カンマ)で区切ることによって複数登録できますし、そのカンマ区切りされたトークンには正規表現を使えます。以下の例はすべて正しい値です。

  • pointcut="run, init"
  • pointcut="[n-u]{3}" (現実的ではない正規表現例ですが、少なくとも"run"がヒットします)
  • pointcut="init, [n-u]{3}"
  • (属性自体を書かない)

このpointcut属性で指定されるコンポーネントメソッドを指して、AOPの用語で「Joinpoint」といいます。Crossing Concernの実装がAdviceであり、Core Concernの実装が行われるコンポーネントのメソッドがJoinpoint、そしてJoinpointの集合定義がPointcutであると言えます。そして、このAdviceとPointcutを組み合わせたもの、つまりはAdviceをJoinpointとを結びつけるものを、「Aspect」と呼びます。Aspectコンポーネントに組み込む作業をAOP用語で「Weaving」といいます。編み物の「編む」を意味するこのWeaving、Seasar2では設定XMLにおける<aspect>エレメントの記述に従ってS2Containerが内部で行います。
AOPは「Aspect Oriented Programing」の略語です。つまりは、アプリケーション機能をCore ConcernとCrosscutting Concernに分類および設計し、それぞれコンポーネントメソッドとAdviceとして実装します。その実装を結びつける設定はPointcutとAdviceをまとめたAspectコンポーネントにWeavingして行うのです。最近現れた軽量コンテナ(Lightweight Container)ではXML等で簡便に設定を行うと、内部的にはバイトコードエンジニアリング等を用いてコンパイル済みのクラス同士を組み合わせる機能を提供し、それがAOPであるとしています。軽量コンテナの一実装であるSeasar2は、いくつかあるAOP機能を持つ軽量コンテナの中でも、Weaving作業がとてもシンプルでわかり易い仕様になっているところに特徴があります。
AOP機能を持つ軽量コンテナ(およびJ2EEコンテナ)がたくさん登場しつつあります。アプリケーションサーバーの分野でAOPが脚光を浴びる理由は、コンテナ設計者がCrosscutting Concernをどう捉えたかにあります。エンタープライズアプリケーションにおける横断的に様々な場所に現れる機能とは何か?今、最新の考え方は、J2EEAPIこそがCrosscutting Concernそのものであるとしています。データアクセス、トランザクション管理、ネームサービス、クラスタリングと様々な機能を提供するJ2EEAPIはこれまで活用するためのAPI仕様の理解と大量のAPIコールをプログラミングする必要がありました。Seasar2をはじめとするAOP機能を持つサーバーは、このJ2EEAPIを積極的にAdviceとして提供し、利用者は設定XMLコンポーネントに対するWeaving作業を行うだけという、極めて開発効率のよいパラダイムを提供しようとしているのです。