スライド 1

アスペクト指向プログラミングと
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