PDF file

概要
• AOPでやりたいこと
• AOPでできること
AOP入門
– 現在の状況
– AspectJの紹介
– 応用例
増原英彦 ([email protected])
• 他のAOP言語
東京大学 大学院 総合文化研究科
SEAフォーラム 2006年6月
1
2
AOPは何をしてくれるか
AOPは何をしてくれるか
複数のモジュールにちらばる記述(横断的関心事)を
一まとめにする:
• 修正・デバグ・レビューを容易にする
• 「いつ・どこで」を明文化する
複数のモジュールにちらばる記述(横断的関心事)を
一まとめにする:
• 修正・デバグ・レビューを容易にする
• 「いつ・どこで」を明文化する
3
4
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
1
AOPとは: 具体例
具体例:図形エディタ
• 例: 図形エディタの内部のモジュール化
– モジュール: 図形要素(点・線・円等)、画面、
命令(生成・移動・削除)など
– with OO: モジュール=クラス
• 効用
– 拡張・修正・デバグ範囲の限定 (例: 図形要素の追加)
• ディスプレイの定義は
図形要素の詳細を
知らずにできる
• 図形要素の種類を
増やすときの
手間が小さい
– ポリシーの明文化
※ アスペクトもモジュール
Display
----------figures
----------redraw()
draw()
FigElm
---------------moveby(dx,dy)
display(disp)
Point
----------------x, y
----------------getX()
getY()
moveby(dx,dy)
setX(x)
setY(y)
display(disp)
5
6
問題: 散らばる記述
aka 横断的関心事
アスペクトによる
モジュール化
• 図形変更時に画面を
再描画したい
• 図形を変更している
場所は沢山ある
• モジュールに
x+=dx; y+=dy;
まとめ
Display.redraw();
られない!
this.x = x;
※ほんの Display.redraw();
一例
this.y=y;
• 図形要素の定義と
再描画が独立
Display
----------FigElm
figures
this.p1=p1;
-------------------------Display.redraw();
moveby(dx,dy)
redraw()
display(disp)
this.p2=p2;
draw()
Display.redraw();
Point
p1.moveby(dx,dy);
p2.moveby(dx,dy);
----------------x, yDisplay.redraw();
----------------getX()
getY()
moveby(dx,dy)
setX(x)
setY(y)
Display.redraw(); display(disp)
Line
----------------p1, p2
----------------getP1()
getP2()
moveby(dx, dy)
setP1(p1)
setP2(p2)
display(disp)
Line
----------------p1, p2
----------------getP1()
getP2()
moveby(dx, dy)
setP1(p1)
setP2(p2)
display(disp)
DisplayUpdating
----------------figureChange()
advice()
Display.redraw();
x+=dx; y+=dy;
Display.redraw();
this.x = x;
Display.redraw();
this.y=y;
Display.redraw();
7
Display
----------FigElm
figures
this.p1=p1;
-------------------------Display.redraw();
moveby(dx,dy)
redraw()
display(disp)
this.p2=p2;
draw()
Display.redraw();
Point
p1.moveby(dx,dy);
p2.moveby(dx,dy);
----------------x, yDisplay.redraw();
----------------getX()
getY()
moveby(dx,dy)
setX(x)
setY(y)
display(disp)
Line
----------------p1, p2
----------------getP1()
getP2()
moveby(dx, dy)
setP1(p1)
setP2(p2)
display(disp)
8
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
2
AOPの現状: 道具
AOPの現状: 使われ方
• 実用的な処理系が揃いつつある
• 3種の使われ方 [Kiczales]
– AspectJ, AspectC++
– AspectWerkz, JBoss AOP, Spring AOP
– exploration / enforcement
– auxiliary / infrastructure
– core / business
• 開発環境もある
– AJDT plug-in for Eclipse
• ライブラリはこれから
for more:
• 状況: 実験的使用 ~
実システムでの部分的使用
– community wiki @ aosd.net
– AOP@Work (IBM developerWorks)
– 商用システムでも (e.g., IBM SWG)
9
10
織込と実行
AspectJ言語
• 最も知られている汎用AOP言語
Java
• バッチコンパイル
• バイトコード織込
– 他のAOP言語の手本
• Java言語と上位互換
• 開発体勢:
Java
ajc
アスペクト
javac
クラス
ajc
• ロード時織込
Java
• 開発環境: Eclipseプラグイン等
アスペクト
11
JVM
aspectjrt.jar
アスペクト
– Xerox PARCで開発がスタート(’90後)
– Eclipse オープンソース開発 (現在)
クラス
javac
クラス
ajc
クラス
クラス
JVM
aspectjrt.jar
aspectj
weaver.jar
JVM
aspectjrt.jar
12
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
3
AspectJの主要概念
AspectJの主要概念
• アスペクト (cf. クラス)
横断的関心事をまとめる単位
• アドバイス (cf. メソッド)
動作
追加的な操作
• 結合点
• ポイントカット
「どんなとき」を決める
• 型間宣言
追加的宣言 構造
•
•
•
•
アスペクト
アドバイス
ポイントカット
型間宣言
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(void Point.setX(int)) ||
call(void Point.setY(int)) ||
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
after() : move() { Display.redraw(); }
void FigElm.draw(Display d);
void Point.draw(Display d) { … }
…}
13
AspectJの主要概念: アドバイス
追加・代替の動作を記述
• どんな動作の(ポイントカット)
• 前/後/かわりに(修飾子)
• 何をするか(本体)
– Javaの文
moveした後は
redraw()を呼べ
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(void Point.setX(int)) ||
call(void Point.setY(int)) ||
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
after() : move() {
Display.redraw();
}
void FigElm.draw(Display d);
void Point.draw(Display d) { … }
…}
14
AspectJの主要概念: ポイントカット
何かが起きたときを
指定
• 動作の種類
(メソッド呼出etc.)
• シグネチャ
• 合成
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(void Point.setX(int)) ||
call(void Point.setY(int)) ||
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
after() : move() { Display.redraw(); }
void FigElm.draw(Display d);
void Point.draw(Display d) { … }
…}
FigElm.movebyまたはPoint.setXまたは・・・を呼出すとき
15
16
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
4
AspectJの主要概念: 型間宣言
(inter-type declarations)
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(void Point.setX(int)) ||
call(void Point.setY(int)) ||
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
既存の型に外から
宣言を追加
• 既存の型
Point
setX
after() : move() { Display.redraw(); }
• 追加される宣言
– メソッド・フィールド
– extends・implements節
public void MyTask.run() { init(); }
Main
FigElmクラスにdraw
メソッドを追加
– クラス・インタフェース
declare parent MyTask:
implements Runnable;
AspectJの実行モデル:
結合点モデル
結合点 = メソッド呼出、実行、
フィールド代入などの
実行中の動作
this.x=x
void FigElm.draw(Display d);
void Point.draw(Display d) { … }
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) || …;
after() : move() { … }
void FigElm.draw(Display d);
void Point.draw(Display d) { … }
…}
…}
MyTaskクラスに
Runnableを実装
17
18
AspectJの実行モデル:
結合点モデル
Main
Point
setX
Display
Updating
AspectJの実行モデル:
aroundアドバイス
• 結合点とアドバイスの
ポイントカットが合致
→beforeの本体;
本来の結合点;
afterの本体の順に実行
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) || …;
after() : move() { … }
void FigElm.draw(Display d);
void Point.draw(Display d) { … }
…}
Main
Point
Lock
Movement
setX
proceed
本来の結合点に
なりかわって実行
• proceed→
結合点の実行を再開
aspect LockMovement {
pointcut move() :
call(int FigElm.moveby(int,int)) || …;
例: ロックされた
図形の移動を禁止
19
…}
void around() : move() {
if (! locked()) proceed();
}
20
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
5
ポイントカットの能力:
横断的な指定
ポイントカットの能力:
ワイルドカード + 命令規則
aspect DisplayUpdating {
FigElm・Point・Lineに
対する動作を
まとめて指定
↓
モジュール化!
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(void Point.setX(int)) ||
call(void Point.setY(int)) ||
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
after() : move() { Display.redraw(); }
…}
DisplayUpdating {
• ワイルドカードに aspect
pointcut move() :
call(int FigElm.moveby(int,int)) ||
よって簡潔に
call(* FigElm+.set*(..));
定義できる
after() : move() { Display.redraw(); }
• 例: FigElmとその … }
子クラスにある
“set”で始まる名前のメソッドが
呼び出されたとき
21
ポイントカットの能力: 様々な条件
• 色々な種類の条件
22
ポイントカットの能力:
文脈情報(self)の取得
画面更新の例
• 各図形に
表示画面が
対応
• アドバイスは
「変更される
図形」から
画面を取得し
て再描画
– within(myapp.db..*): DBパッケージ内のみ
– set(int Point.x): Point.xへの代入
– withincode, execution, get, handler,
initialization, static initialization
• 組み合わせる
– call(* javax.swing..*(..))
&& !within(myapp.ui..*)):
UIパッケージ以外からのSwing呼出し
23
aspect DisplayUpdating {
pointcut move(FigElm fig) :
(call(int FigElm.moveby(int,int)) ||
call(void FigElm+.set*(..)))
&& target(fig);
after(FigElm fig) : move(fig) {
Display d = fig.getDisp();
d.redraw(fig);
}
…}
呼出先のオブジェクト: fig
24
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
6
ポイントカットの能力:
制御の流れ(cflow) 1
• p.moveby(2,3);は
3回redrawを
呼んでしまう
ポイントカットの能力:
制御の流れ(cflow) 2
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(* FigElm+.set*(..));
after() : move() { Display.redraw(); }
…}
setX
• 呼出スタックを
調べられる →
「setX, setYが
movebyなどから呼出
されていないとき」
aspect DisplayUpdating {
pointcut move() :
call(int FigElm.moveby(int,int)) ||
call(* FigElm+.set*(..));
after() : move()
…}
&&
!cflowbelow(move()) { … }
setY
moveby
main
setX
class Point … {
void moveby(int dx, int dy) {
setX(getX()+dx);
setY(getY()+dy); } }
setY
moveby
main
class Point … {
void moveby(int dx, int dy) {
setX(getX()+dx);
setY(getY()+dy); } }
25
26
再利用: 抽象アスペクト
• 抽象アスペクト
– 「どこ」 = 抽象
ポイントカットとして
定義を遅らせる
– 動作 = アドバイス
に定義する
• 具体アスペクト
– ポイントカットを
具体化するだけ
AOPの応用例
abstract aspect AbstractLogging {
abstract pointcut logPoint();
after() : logPoint() {
…ログ取り動作... }
…}
• Architecture enforcement
– API Scanner @ IBM SWG
• 例外処理
aspect DBLogging
extends AbstractLogging {
pointcut logPoint():
call(* myapp.db..*.*(..));
}
27
slide courtesy of Gregor Kiczales
28
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
7
slide courtesy of Gregor Kiczales
slide courtesy of Gregor Kiczales
Architecture Enforcement
Architecture Enforcement –
Modules
public aspect ArchitectureEnforcement {
insurance.ui
insurance.model.listeners
insurance.model.
insurance.model.validation
public pointcut uiCall():
(call(* insurance.ui..*(..))
|| call(insurance.ui..new(..))
&& !call(* java.lang.Object.*(..));
public pointcut modelCall():
<similar>;
insurance.model.impl
public pointcut modelImplCall() :
<similar>;
persistence
insurance.dao
...one per module...
insurance.dao.hibernate
insurance.dao.inmemory
29
slide courtesy of Gregor Kiczales
30
slide courtesy of Gregor Kiczales
Architecture Enforcement –
Modules
Architecture Enforcement –
Rules
...
...
public pointcut inUI():
within(insurance.ui..*);
declare warning: uiCall() && !inUI():
"No calls into the user interface";
declare warning: modelImplCall() && !inModelImpl():
"Please use interfaces in insurance.model instead";
public pointcut inModel():
within(insurance.model.*);
declare warning: daoCall() && !(inModelImpl() ||
inAnyDAO()):
"Only model and DAO implementers should use DAO
interface";
• プログラマブル・柔軟性が高い
• 1つのツールであらゆる
アーキテクチャを扱うのは難しい
public pointcut inModelImpl():
within(insurance.model.impl..*);
...one per module...
31
32
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
8
slide courtesy of Gregor Kiczales
slide courtesy of Gregor Kiczales
Architecture Enforcement At Work
Example: API Scanner
• IBM SWGで利用されているアスペクト群
–
–
–
–
30のプロジェクト/製品で利用
良くない場合をdeclare warningで検知
1つのプロジェクト/製品は他のを使用する環境
例: publicだけど外部I/Fではないメソッドの呼出
• 配布しやすいスクリプトにまとめられている
• 50,000以上の問題点を発見
– 設計のモジュール性を尊重すれば自由度が上がる
– 将来の製品開発の時間短縮の可能性
33
slide courtesy of Gregor Kiczales
34
slide courtesy of Gregor Kiczales
Example: Preliminary Exception Management
Example: Exception
Management
package insurance.ui;
import ...;
insurance.ui
public aspect ExceptionHandling {
private static final String title =
"Simple Insurance Exception";
RuntimeException
Object around() : SystemArchitecture.modelCall()
&& SystemArchitecture.inUI()
&& !within(ExceptionHandling) {
Object ret = null;
try {
ret = proceed();
} catch (SIException ex) {
MessageDialog.openError(SimpleInsuranceApp.getShell(),
title,
"Call to "+ thisJoinPoint +" threw exception¥n¥n" +
ex.getMessage());
}
return ret;
}}
insurance.model
throws…
SIException
insurance.dao
throws…
SIPersistenceException
35
36
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
9
他のAOP言語
AOPはどんな場合に使えるのか?
(実用に耐えられそうなもののみ)
• 「いつそれをやるか」が単純でない場合
• Javaアプリケーションフレームワーク
– 特定の動作だけログをとる
– このモジュールだけ例外を別扱い
– 特徴: pure Javaの記述 (メタファイル・アノテーション)
– ライブラリ: 永続化・キャッシュ等
– 処理系:
• AspectWerkz (BEA) ― AspectJと共通化
• JBoss AOP
• Spring AOP ― AspectJと共通化?
• かつ規則化したい場合
– 将来の拡張・変更のため
– 力ずくで100箇所にコードを書くと後で泣く
そうでなければOOでrefactoringすべき
• Java以外: AspectC++
37
38
まとめ
• AOPとはモジュール化の手法
• 使えるところから使われている
• AspectJの紹介
– 結合点・ポイントカット・アドバイス
– 型間宣言
– 応用例
• 他のAOP言語: 共通化が進んでいる
39
SEA Forum 「アスペクト指向技術は実用に使えるか」講演資料 2006年5・6月
10