Comments
Description
Transcript
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