アスペクト指向プログラミングと Dependency Injection の融合 数理・計算科学専攻 千葉研究室 石川 零 指導教官:千葉 滋 目標:後から簡単に変更できるプロ グラムの開発 プログラムの開発 一度完成したら終わり、ではない バグの修正、機能の拡張 →後から簡単に変更できるよう設計することが重要 簡単に変更できるようにするには? 変更箇所を少なくする 変更箇所を1つにまとめる 修士論文発表会 2 コンポーネントを用いた開発 小さな部品(コンポーネント)を組み立てて、プログ ラムを作る 既存のプログラムの部品を“組み替える”だけで、新し いプログラムを作ることが可能 後からの変更が簡単 例 : オンライン書店のためのプログラムの開発 Amazon.com のようなもの 後からDB システムを高性能なものに変更 利用者の増加に伴い DB を操作するための機能が1つの部品になっていれば、そ の部品を交換するだけでよい 修士論文発表会 3 オブジェクト指向プログラミングを用 いた設計 コンポーネントは、クラスとして設計 コンポーネントの内部に別なコンポーネントを利用する コードを記述することで、組み立てる コンストラクタ呼び出し メソッド呼び出し フィールド宣言 例:オンライン書店プログラム 注文を発注するコンポーネント db.send(data); DB 操作のための コンポーネント メソッド呼び出しによる結合 DB 修士論文発表会 4 問題点:組み替えが 簡単ではない 組み替えが起こりそうな箇所を ”予測して” 準備 しないと、組み替えは困難 我々の考察では 変更箇所が散らばってしまう 例: DB コンポーネントの交換を簡単にするには ファクトリ、インタフェースを用いて準備 注文送信コンポーネント DB db = DBFactory.make(); db.send(data); MySQL 用DB 操作 コンポーネント DBFactory Oracle 用DB 操作 コンポーネント 変更箇所はファクトリ内部のみ 修士論文発表会 5 組み替えを予測するのも困難 起こりうる変更例:インタフェースの変更 Oracle はDB アクセスの最適化アルゴリズムにヒントを与える 機能を提供していた → 利用したい! 注文送信コンポーネント テスト用 DBFactory class OrderingService { DB db = DBFactory.make(); void addShippingRate( Data data) { db.sendHint(hint); db.send(result); } } MySQL 用 void sendHint() Oracle 用 上位コンポーネントと DB インタフェース、 他の DB コンポーネントの修正が必要! インタフェースやファクトリでは、 修士論文発表会 予測できない変更は対応できない 6 提案:glue コードを用いた設計 コンポーネントを結合するコードを、外側に分離 変更箇所を1つにまとめる GluonJ : glue コードを用いた設計を支援するシステム これまでの実装 GluonJ による実装 問題点の整理 一度組み立てたコンポーネントの組み替えは困難 組み替えを予測して準備しないと、修正箇所が散らばる 全ての組み替えの予測は困難 原因:コンポーネント内に結合のためのコードを記述する組み立て方 修士論文発表会 7 コンポーネントの外側に分離すべき 結合 結合には3種類 フィールド宣言 生成と代入 メソッド呼び出し 1. 2. class OrderingService { 1. DB db = new MySQL(); 2. void addShippingRate( 既存技術による分離 Data data) { ファクトリパターン、 ... Dependency Injection 3. /* 配送代金の追加 */ 2 を分離 db.send(result); } アスペクト指向プログラミング } 1 を分離 3. 注文発注のためのコンポーネント 2, 3 の分離は間接的 修士論文発表会 8 GluonJ が可能にする結合の分離 1. フィールド宣言 2. 生成と代入 3. アスペクト指向プログラミングの技術を応用 Dependency Injection の技術を応用 メソッド呼び出し アスペクト指向プログラミングの技術を、結合を より直感的に記述できるよう改良 生成 フィールド 呼出 GluonJ ○ ○ ○ ○ × × △ ○ △ DI 修士論文発表会 AOP 9 GluonJ を用いて実装したオンライン 書店システム 結合するためのコードは、glue コード に分離して記述 1. 2. 3. DB 型のフィールド宣言 DB コンポーネントの生成と代入 DB コンポーネントのメソッド呼び出し 注文発注コンポーネント class OrderingService { void addShippingRate( Data data) { ... /*配送代金の追加*/ } Data result; } glue コード MySQL 用 MySQL Oracle db db== new MySQL Oracle (); (); db.send(this.result); db.sendHint(hint); sendHint(); Oracle 用 変更が必要な箇所は、glue コードに まとまっている 修士論文発表会 10 予測しない変更を簡単に 起こりうる変更例:サブコンポーネントの追加 DB アクセスをともなうメソッドの冒頭でアクセス権をチェック 注文送信コンポーネント class OrderingService { DB db = DBFactory.make(); void addShippingRate( Data data) { glue コード アクセス権検査 コンポーネント Checker checker = Factory.make(); checker.check(id); db.send(result); } } 実行時に合成 修士論文発表会 11 結合のためのコードは glue コードに 分離 言語機構 glue コード <reference> フィールド宣言 2つの言語機構 2. 生成と代入 <behavior> <reference> タグ 1. 分離するコード メソッド呼出 DB 型のフィールド宣言 DB コンポーネントを生成して代入するコード <behavior> タグ 3. DB コンポーネントのメソッド呼び出し 修士論文発表会 12 <reference> タグの使い方(1): フィールド宣言の分離 言語機構 <reference> フィールド宣言 <reference> MySQL OrderingService.db ; </reference> 分離するコード 生成と代入 <behavior> メソッド呼出 タグの中にフィールドの宣言を記述 フィールドが新たに追加される 既に存在すれば、そのフィールドが使われる 例:MySQL 型のフィールドを、注文発注クラスに追加 追加するフィールド名 : db 修士論文発表会 13 <reference> タグの使い方(2): 生成と代入をするコードの分離 言語機構 <reference> MySQL OrderingService.db = new MySQL(); </reference> <reference> フィールド宣言 生成と代入 <behavior> メソッド呼出 “=” の右側はコンポーネントを生成するコード 分離するコード MySQL コンポーネントの生成 コンポーネントの生成には Java コードを用いて記述 “=“ の左側は代入先を指定 注文発注クラスのフィールドに代入 修士論文発表会 14 <behavior> タグの使い方: メソッド呼び出しの分離 呼び出す箇所の指定 : <pointcut> タグ 言語機構 <reference> フィールド宣言 AspectJ の言語機構を利用 注文発注コンポーネントのメ ソッド内 生成と代入 <behavior> 呼び出すメソッドの指定 : <after> タグ 分離するコード Java コードで記述 db フィールドの差すDB コン ポーネントの、 send() メソッド を呼び出す <before>,<around> も有り メソッド呼出 <behavior> <pointcut> execution(void OrderingService. addShippingRate(..)) </pointcut> <after> this.db.send(this.result); </after> </behavior> 修士論文発表会 15 GluonJ の処理系の実装 Java 言語用の処理系を実装済み 既存のクラスに glue コードに記述された処理を合成 Javassist を利用して実装 JBoss 上で動くアプリケーションにも合成できる 元のファイルは変更しない JBoss : アプリケーションサーバ JBoss のクラスローダの拡張機構を利用して実装 これまでの利用 J2EE アプリケーションに対するスケジューリング機能の追加 [日比 野] に利用 KLAS システム [柳澤] は、処理系の実装に GluonJ の処理系の パーザ部分を利用 修士論文発表会 16 結合のためのコードの分離を目的と する既存技術 Dependency Injection (DI) 分離できるのは生成と代入のためのコードのみ アスペクト指向プログラミング (AOP) 分離するコンポーネントをアスペクトで書かなけれ ばいけない アスペクトを組み立て用のコードの分離のみに用い るという方法もあるが、間接的 修士論文発表会 17 アスペクトで書くのがいけない理由 コンポーネントの開発者にとって制約 AOP システムに依存した文法で記述 new できない (AspectJ など) メソッドシグネチャに制限 (JBoss-AOP など) コンポーネントの再利用性を低下 アスペクト = 分離したい処理 + 呼び出し箇所の指定 (アドバイス) (ポイントカット) 呼び出し箇所の指定が、結合するコンポーネントに依存 修士論文発表会 18 AOP を用いたもう1つの方法: アスペクトを結合の分離のみに利用 AOP のプログラミング技術を駆使すれば分離可能 アスペクトをglue として用いる 生成と代入、フィールドの追加の分離 インタータイプ宣言を利用 メソッド呼び出しの分離 ポイントカットとアドバイスを利用 注文発注 コンポーネント glue アスペクト インタータイプ 宣言 MySQL OrderingService.db = new MySQL(); ポイントカット アドバイス MySQL execution (addShippingRate(Data)) && this(s) 修士論文発表会 s.db.send(data); 19 アスペクトを glue として使う問題点 (1): 代入が間接的 既存のフィールドに代入するコードを、直接分離する機 能がない アドバイスを用いて記述→煩雑に 追加したフィールドへの代入を分離する方法と異なる GluonJ reference タグを用いて代入 追加したフィールドも、既存のフィールドも統一的に扱える AspectJ による記述 GluonJ による記述 <reference> OrderingService.db = new MySQL(); </reference> after(OrderingService s) : (new OrderingService(..)) && this(s) { s.db = new MySQL(); } 修士論文発表会 20 アスペクトを glue として使う問題点 (2): 実行時オーバヘッドの存在 分離したコンポーネントの呼び出しには常に、 glue アスペクトの呼び出しが伴う 多用しすぎると実行速度に影響 マイクロベンチマークによるオーバヘッドの測定 空のメソッドにカウンタアドバイスの呼出を挿入 1000万回の実行にかかった時間を比較 オーバヘッドの測定結果 全てのコンポーネントを glue を使って組み 立てるとなると、影響が出るのでは 実行時間 AspectJ 188 ms GluonJ 修士論文発表会 35 ms 21 まとめ glue コードを用いた開発の提案 コンポーネント同士を組み立てるためのコードを分離して記述 GluonJ :glue コードを用いた開発を支援するアスペクト指向シス テム 発表済み論文 “Aspect-Oriented Programming beyond Dependency Injection”. 千葉, 石川. ECOOP 2005. “GluonJ によるビジネスロジックからのデータベースアクセスコー ドの分離 ”. 石川, 千葉. SPA 2005. “アスペクト指向プログラミングと Dependency Injection の融合” . 石川, 千葉. Tech-Report C-220 修士論文発表会 22
© Copyright 2024 ExpyDoc