AspectJ

AspectJ 簡易リファレンス

このページは,AspectJ Project が公開している AspectJ Quick Reference (英語) の内容に基づいた簡易リファレンスです.厳密な構文定義などは書いていませんので,簡易サンプル集といった感じになっています.いくつか,勝手に補足した部分もあります.

アスペクトの定義について詳しく知りたい方は,AspectJ の Programming Guide (英語)を読むのが一番確実です.ポイントカット定義のやり方については,書籍で紹介している日本語のAspectJ本が,かなり整理された形になっているので,お勧めです.

アスペクトの定義

トップレベル(通常,クラス定義を書く位置)において,アスペクト A を定義するには,以下のような記述になります.

aspect A { … }

また,private フィールドやメソッドにアクセスする必要があるアスペクトは,「特権」を持っていることを明示した定義になります.

privileged aspect A { … }

アスペクトが,他の抽象アスペクト B を継承したり,インタフェース I, J を実装したい場合には次のようになります.

aspect A extends B implements I, J { … }

アスペクトのインスタンスは,通常ただ1つだけ作成されます.もし,複数のインスタンスを生成したい場合には,perXXX 宣言を使います.

// void Foo.m() への呼び出しごとにインスタンスが生成される例
aspect A percflow( call(void Foo.m()) ) { … }

以下,一般形です.

[ privileged ] [ Modifiers ] aspect Id
[ extends Type ] [ implements TypeList ] [ PerClause ]
{ Body }

PerClause としては,pertarget, perthis, percflow, percflowbelow, issingleton (デフォルト)を取ることができます.

ポイントカット:型宣言中(普通はアスペクトの中)に記述

ポイントカットの定義で使用可能な述語(call, set など)については別記します.

privateな(外部から見えない)ポイントカット定義は,以下のように書きます.pcがポイントカットの名前,":" 以降がポイントカットの中身です.

private pointcut pc() : call(void Foo.m()) ; // void Foo.m() への呼び出しにマッチ

何も修飾しなければ,パッケージレベルの可視性を持ちます.

// 以下のポイントカットは,int Foo.x への代入文にマッチします.
// 仮引数 int i は,args(i) によって Foo.x の代入値に対応させられています.
// i の値には,アドバイス定義からアクセス可能となります.
pointcut pc(int i) : set(int Foo.x) && args(i) ; 

abstract を付加すると,抽象ポイントカットとなり,後で(継承したアスペクトで)ポイントカットの定義を行うことになります.また,public 宣言をつけることで,外部から参照可能となります.

public abstract pointcut pc();

この例は,同一パッケージから可視であるような抽象ポイントカットの定義です.仮引数 Object o は,ポイントカット定義側でアクセス可能にする必要があります.

abstract pointcut pc(Object o) ;

一般形を以下に示します.

abstract [Modifiers] pointcut Id ( Formals ) ;
[Modifiers] pointcut Id ( Formals ) : Pointcut ;

アドバイス:アスペクト内に記述

アドバイスは,与えられたポイントカットに対して,そのイベントの直前・直後,あるいはそのイベントの代わりに実行されるべき処理の定義です.

以下は,before アドバイスの例です.フィールド int Foo.y を参照する直前に実行されるコードを定義します.

before () : get(int Foo.y) { ... }

上の例では直接("プリミティブ・ポイントカット" を使って)ポイントカット記述を行っていますが,定義済みのポイントカットを利用することもできます.定義済みのポイントカットを,他の定義済みポイントカットなどと組み合わせることも自由です."&&", "||", "!" による演算で,共通部分・和集合・補集合を選択することができます.

pointcut setter() : set(int Foo.y);
pointcut getter() : get(int Foo.y); 
before(): getter() { ... }
after(): getter() || setter() { ... }

以下は,after アドバイスの例です.int Foo.m(int) に対するメソッド呼び出しが正常終了(例外を投げられていない)した直後に,以下のアドバイスは実行されます.

after () returning : call(int Foo.m(int)) { ... } // "returning" が正常終了を意味します.

after アドバイスの実行時に,戻り値にアクセスしたい場合には,以下のように記述します.この場合,アドバイス本体では戻り値が変数 x としてアクセス可能になります.

after () returning (int x) : call(int Foo.m(int)) { ... }

after アドバイスで,例外を投げられた場合だけを扱う場合には,throwing という記述を使います.

after () throwing : call(int Foo.m(int)) { ... }

after アドバイスで,投げられた例外にアクセスしたい場合には,throwing の後ろに,パラメータを定義します.この場合,NotFoundException (とそのサブクラス)が投げられた場合にだけ,このアドバイスが実行され,アドバイス定義の中では変数 e として例外オブジェクトにアクセスできます.

after () throwing (NotFoundException e) : call(int Foo.m(int)) { ... }

after アドバイスで,正常終了・例外終了を区別したくない場合は,単純に returning/throwing を省略します(戻り値にはアクセスできません).

after () : call(int Foo.m(int)) { ... }

アドバイス定義では,引数を用いることもできます.int i を仮引数として定義し,set(int Foo.x) によってマッチする Foo.x への代入文に対して,その代入されるはずの値を args(i) という述語によって,仮引数 i に設定させます.

before(int i) : set(int Foo.x) && args(i) { ... } // アドバイス定義内で, i は Foo.x に代入されることになる値

ポイントカット定義ではワイルドカードが使えますから,引数の型が不明な場合には,Object 型を使うことができます.int 型は Integer などに,自動で変換されます.以下は,Foo の任意のフィールドへの代入直前に実行されるアドバイスで,代入される値を変数 o としています.

before(Object o) : set(* Foo.*) && args(o) { ... }

around アドバイスは特殊なアドバイスで,本来実行されるはずだった文を実行せず,かわりに処理が実行されます.

以下の例では,int Foo.m(int) の呼び出しが起きたときに,Foo.m は実際には実行されず,以下のアドバイス本体だけを実行して,プログラムは先へ進むことになります.そのため,アドバイス本体は代わりの戻り値を返す必要があります.

int around () : call(int Foo.m(int)) { ... }
// 以下は,Foo.m への呼び出し結果を(引数が何であれ)とりあえず 0 にする例
int around () : call(int Foo.m(int)) { return 0; } 

例外を投げる可能性がある場合,throws 節を記述することもできます.

int around () throws IOException : call(int Foo.m(int)) { ... }

本来実行されるべき処理を実行したい場合,proceed キーワードを使います.

// Foo.m へのメソッド呼び出しを行った結果に +1 して返す例です.
int around () : call(int Foo.m(int)) { return proceed() + 1; }

一般形は以下のとおりです.

[ strictfp ] AdviceSpec [ throws TypeList ] : Pointcut { Body }
AdviceSpec としては,以下が使用可能です.
before ( Formals )
after ( Formals )
after ( Formals ) returning [ ( Formal ) ]
after ( Formals ) throwing [ ( Formal ) ]
Type around ( Formals )

アドバイス内部で使えるもの

アドバイスの中に記述するのは,通常の Java コードです. 定義した引数には,ポイントカットの this,target,args や after returning などで値を割り当てて使用することができます.そのほか,アドバイスが実行されたタイミングで得られる情報にアクセスしたい場合,thisJoinPoint 変数が使用可能です.また,ソースコード情報など,静的に決まる部分だけを表す StaticPart の変数もあります.

thisJoinPoint // JoinPoint クラスのオブジェクト
thisJoinPointStaticPart  // thisJoinPoint.getStaticPart() でも OK
thisEnclosingJoinPointStaticPart // thisJoinPoint の "親" イベントのソース位置情報

around アドバイス内では,proceed キーワードが利用可能です.本来実行されるはずだった Join Point を実行することができます(callポイントカットに対してアドバイスを付けているならメソッド呼び出しが起きます).引数として,around advice の仮引数として定義したものを渡す必要があります.メソッド呼び出しの対象や引数の値を差し替えるために使用可能です.

// 基本構文
proceed ( Arguments )
// 以下は,Foo.m(x) のメソッド呼び出しを,Foo.m(x+1) に変換するアドバイスです.
int around (int i) : call(int Foo.m(int)) && args(i) { return proceed(i+1); }

インタータイプ宣言: アスペクト内に記述

インタータイプ宣言とは,アスペクトの中に,他のクラスが持つべきメソッド・フィールドを記述する機構のことです.構文的には,メソッド名やフィールド名の直前に,そのメソッドやフィールドが追加される対象のクラス名が入っているだけだと考えると理解しやすいと思います.

以下は,クラス Foo に,メソッド m を追加する例です.

int Foo.m ( int i ) { ... } // このメソッド内で,this は Foo のインスタンスを指すことに注意

以下は,private メソッドを追加する例です.この private は,「定義したアスペクト以外からはアクセスできない」という意味です.

private int Foo.m ( int i ) throws IOException { ... }

抽象メソッドも追加できます.

abstract int Foo.m ( int i ) ;

コンストラクタは,メソッド名 new として定義します.

Point.new ( int x, int y ) { ... }

static フィールドの追加なども可能です.private なのでこの定義したアスペクトからのみ参照可能です.

private static int Point.x ;

フィールドを定義するときには,その初期化も同時に定義することができます.以下の例では,Point.x を初期化していますが,このとき this はアスペクトではなく Point のインスタンスを指すことに注意してください.

private int Point.x = foo() ;

一般形は以下のようになります.

[ Modifiers ] Type Type . Id ( Formals ) [ throws TypeList ] { Body }

abstract [ Modifiers ] Type Type . Id ( Formals ) [ throws TypeList ] ;

[ Modifiers ] Type . new ( Formals ) [ throws TypeList ] { Body }

[ Modifiers ] Type Type . Id [ = Expression ] ;

特殊なインタータイプ宣言:アスペクト内に記述

アスペクトは,他のクラスの親子関係を変更させることができます. クラス C がクラス D の子であることを,以下のように定義することができます. ただし,Java では多重継承はできませんので,D は,C の本来のスーパークラスのサブクラスである(C と,Cのスーパークラスの間に入っても問題が起きない)必要があります.

declare parents : C extends D;

インタフェースについても定義が可能です.このときは,C が I,J のメソッドを(インタータイプ宣言での定義も含めて)実装している必要があります.

declare parents : C implements I, J ;

declare warning/error 宣言は,指定したポイントカットが存在する場合に警告・エラーメッセージを生成することができます.特定のメソッド呼び出しを禁止するなど,何らかのルールを定義したいときに使用します.

// Point クラス外からの Point へのフィールド代入を "bad set" として警告します.
declare warning : set(* Point.*) && !within(Point) : “bad set” ;

// Singleton に対するすべてのコンストラクタ呼び出しをエラーとします.
declare error : call(Singleton.new(..)) : “bad construction” ;

declare soft 宣言は,発生するはずの例外を,SoftException 型でラップします.SoftException は RuntimeException のサブクラスで,throws 節の定義などを回避することができます.

// Foo のコンストラクタ実行中に発生した IOException をラップします.
declare soft : IOException : execution(Foo.new(..));

declare precedence 宣言は,アスペクトの優先順位を定義します.優先度が高いアスペクトは,より外側で実行されます.すなわち,before アドバイスは優先度が高いものから順番に実行され,Join Point で本来の処理が実行され,after アドバイスは優先度が低いものから順番に実行され,最後に優先度が高いアスペクトの after アドバイスが実行されます.

// セキュリティアスペクトの before アドバイスを,他のアスペクトより先に動作させます.
// 以下の定義では,Security-before, Logging-before, その他, Logging-after, Security-after の順で実行となります.
declare precedence : Security, Logging, *;

一般形は以下のとおりです.

declare parents : TypePat extends Type ;
declare parents : TypePat implements TypeList ;
declare warning : Pointcut : String ;
declare error : Pointcut : String ;
declare soft : Type : Pointcut ;
declare precedence : TypePatList ;

プリミティブ・ポイントカット:ポイントカット定義に使える述語

プリミティブ・ポイントカットは,実行中のイベントJoin Point)をとらえるもの,イベントの範囲を限定するためのもの,そのイベントで使われているデータに対する条件,に大別されます.

基本のポイントカット:メソッド呼び出しと実行,フィールドの代入・参照

AspectJ で基本の Join Point は,やはりメソッドの実行です. call, execution は,それぞれ,メソッドの呼び出しと実行を表現します. コンストラクタは,戻り値を持たない new という名前のメソッドとして表現されます.

// void Foo.m(int) に対するメソッド呼び出しにマッチ
call ( void Foo.m(int) ) 

// Foo クラスのすべてのコンストラクタ呼び出しにマッチ
call ( Foo.new(..) )     

// Foo のメソッドで,IOException を投げるもの,すべての実行にマッチ
execution ( * Foo.*(..) throws IOException ) 

// Foo クラスの public でないコンストラクタの実行にマッチ
execution ( !public Foo .new(..) )

おそらく次に重要となるのが,フィールドの参照と代入です.

// フィールド Point.x の参照にマッチ
get ( int Point.x )

// Point クラスの private でないすべてのフィールドへの代入にマッチ
set ( !private * Point.* )

例外ハンドラ,アドバイス実行をとらえる

例外ハンドラ,アドバイスの実行には,それぞれ handler, adviceexecution が用意されています.例外ハンドラは引数として例外の型を指定しますが,アドバイス実行はすべてのアドバイスにマッチします.

// IOException か,そのサブクラスの例外が catch ブロックに捕捉されたときにマッチ.
// Note: handler に対しては,before アドバイスのみが利用可能
handler ( IOException+ )

// すべてのアドバイス実行にマッチします.引数は取りません.
adviceexecution()

クラスの初期化とオブジェクトの初期化をとらえる

コンストラクタに対しては,呼び出しと実行以外に,「初期化」というタイミングがあります.それに対応して,専用のポイントカットが用意されています.

まず,クラスの初期化に対してマッチする,static initialization です.これは,最初にクラス名が登場するとき(クラスがロードされるとき)に,static {} でくくられたコード(static フィールドの初期化)が実行されるタイミングです.

// Foo がロードされた後の static イニシャライザの実行にマッチ
staticinitialization( Foo )

次に,pre-initialization です.これは,オブジェクトのインスタンスが生成された直後の,そのインスタンスを初期化するための最初のコンストラクタ呼び出しに該当します.つまり,コンストラクタの中で最初に実行される this() や super() よりも前に実行されます.

// Foo.new(int) のコンストラクタ実行前にマッチ
// Note: preinitialization に対しては, around アドバイスは使用禁止
preinitialization ( Foo.new(int) )

最後に,initialization があります.これは,this() や super() によるオブジェクトの初期化(の1ステップ)が終わるごとにマッチします.

// Foo.new(int) コンストラクタによって開始された Foo オブジェクトの初期化にマッチ
// Note: initialization に対しては, around アドバイスは使用禁止
initialization ( Foo.new(int) )

おそらく上記の説明だけでは理解しにくいと思うので,以下に,例を示します. 以下は,クラス Foo と,それを継承したクラス Bar のコードです. Foo のコンストラクタは2つあり,Foo.new() が内部で Foo.new(int) を呼び出しています.

Foo.java
1:  class Foo {
2:    int f;
3:   
4:    public Foo() {
5:      this(0);
6:      System.err.println("Foo.new() body");
7:    }
8:  
9:    public Foo(int i) {
10:     f = i;
11:     System.err.println("Foo.new(int) body");
12:   }
13: }

Bar.java
1: class Bar extends Foo {
2:   public Bar() {
3:     super();
4:     System.err.println("Bar.new() body");
5:   }
6: }
LogginAspect.java
50: public static void main(String[] args) {
51:   Foo foo = new Bar();
52: }

以上のようなコードに対して,

 pointcut preinit(): preinitialization(Foo+.new(..));
 pointcut init(): initialization(Foo+.new(..));
 pointcut calls(): call(Foo+.new(..));
 pointcut exec(): execution(Foo+.new(..));

という4つのポイントカットを定義して,それぞれに以下のようなロギングのための before/after アドバイスを定義します.

 // call に対して,"before-call" を出力させる
 before(): calls() {
   System.err.print("before-call: ");
   System.err.println(thisJoinPointStaticPart.getSourceLocation());
 }

そうすると,LoggingAspect 51行目の Foo foo = new Bar(); という文に対して,次のような順序でプログラムが実行されます.

before-call: LoggingAspect.aj:51
before-pre-init: Bar.java:2
after-pre-init: Bar.java:2
before-pre-init: Foo.java:4
after-pre-init: Foo.java:4
before-init: Foo.java:4
before-execution: Foo.java:9
Foo.new(int) body
after-execution: Foo.java:9
before-execution: Foo.java:4
Foo.new() body
after-execution: Foo.java:4
after-init: Foo.java:4
before-init: Bar.java:2
before-execution: Bar.java:2
Bar.new() body
after-execution: Bar.java:2
after-init: Bar.java:2
after-call: LoggingAspect.aj:51

コンストラクタに対する呼び出し(call ポイントカット)が最初に発生し,次に preinitialization が起きます. その次に,親クラスである Foo の initialization が1回起きている間に, Foo.new(int) と Foo.new() の2つの実行が発生しています. そして,子クラスである Bar の initialization が起きた後, コンストラクタ呼び出しが終了します.

Join Point の出現位置に基づくポイントカット

以下は,ソースコード位置,あるいは実行中の情報に基づいて,Join Point の一部を選択するために使われるポイントカットです.

within, withincode は,ソースコード位置に基づいて Join Point を選択するポイントカットです.

// com.bigboxco パッケージに定義されたコードで起きるすべての Join Point にマッチ
within ( com.bigboxco.* )

// Figure.move メソッドに書かれたコードの中で起きるすべての Join Point にマッチ
withincode ( void Figure.move() )
// com.bigboxco パッケージのすべてのクラスのコンストラクタのコード中で起きる Join Point にマッチ
withincode ( com.bigboxco.*.new(..) )

cflow および cflowbelow は,特定の Join Point の開始から終了までに発生する一連の Join Point すべてを選択します.

// Figure.move 呼び出しの開始から終了までに起きる Join Point (Figure.move 呼び出し自身を含む)すべてにマッチ
cflow ( call(void Figure.move()) )
// Figure.move 呼び出しの開始から終了までに起きる Join Point (Figure.move 呼び出し自身は除く)すべてにマッチ
cflowbelow ( call(void Figure.move()) )

実行時のコンテキストに基づくポイントカット

this,target,args の3つは,各 Join Point で有効なデータを使ってマッチを行うポイントカットです.

this は,call であれば呼び出し側,execution であればメソッドを実行するインスタンスが割り当てられます.

以下は,該当インスタンスが Point クラスかどうか,という判定です.

this ( Point )

アドバイスの仮引数を割り付けることで,this の値をアドバイス本体からアクセス可能にすることができます.

// Point クラスでのメソッド実行に対して,実行中のインスタンスを p とする
before(Point p) : execution(* Point.*) && this(p) { ... }

target は,call であれば呼び出し先,execution ではメソッド実行中のインスタンス,set や get であれば代入対象を指します.

// 対象インスタンスが java.io.InputPart であるようなすべての Join Point にマッチ
target ( java.io.InputPort )

アドバイスの仮引数を割り付けることもできます.

// Point クラスへのメソッド呼び出しに対して,呼び出し相手のインスタンスを p とする
before(Point p) ; call(* Point.*) && target(p) { ... }

args は,そのメソッド呼び出しや,フィールドに設定される値など,引数の型を指定します.やはり,通常は call や execution と組み合わせ,アドバイスの仮引数を使って,アドバイス本体から,引数の内容をアクセス可能にするために使われます.

// 1つめの引数に java.io.InputPart,2つめの引数に int を取る Join Point にマッチ
args ( java.io.InputPort, int )

// 1つめの引数の型が何でも良い場合に,ワイルドカード "*" を使った例
args ( *, int )

// ".." によって,引数をいくつか(0個以上)省略できる
args ( short, .., short )

this/target/args に格納されるデータを簡単にまとめると次のようになります.なお,thisは,クラスメソッド(staticメソッド)に対しては null になる点には注意してください.

ポイントカットthistargetargs
callメソッド・コンストラクタを呼び出すオブジェクト呼び出されるインスタンス(クラスメソッド,コンストラクタの場合,存在しない)メソッドの引数
executionメソッドを実行しようとしているオブジェクト(呼び出された側)thisと同じメソッドの引数
set現在処理を実行しているオブジェクトフィールド代入されるオブジェクトフィールドに代入される値
get現在処理を実行しているオブジェクトフィールド参照されるオブジェクトなし

オブジェクトの状態などの条件を使用したポイントカット

if は,bool 式を取り,各 Join Point の時点で式の評価を行い,true が返されたときだけマッチします.条件式としては,静的メソッド・フィールド,アスペクトの持つフィールド,そのポイントカットでアクセス可能な変数(thisやtargetで束縛した変数)を使用可能です.

// Tracing.isEnable() メソッドが true を返すときだけマッチ
pointcut enabled(): if ( Tracing.isEnabled() )

通常は,他のポイントカットと組み合わせて使われます.アドバイス本体の中で if 文で分岐する場合よりも,コンパイラの最適化が働きます(参照:http://www.eclipse.org/aspectj/doc/next/README-12.html#LAZY_TJP ).

ポイントカットの一般形

ここまで登場したプリミティブ・ポイントカット定義の一般形は以下のとおりです.

call(MethodPat)
call(ConstructorPat)
execution(MethodPat)
execution(ConstructorPat)
initialization(ConstructorPat)
preinitialization(ConstructorPat)
staticinitialization(TypePat)
get(FieldPat)
set(FieldPat)
handler(TypePat)
adviceexecution()
within(TypePat)
withincode(MethodPat)
withincode(ConstructorPat)
cflow(Pointcut)
cflowbelow(Pointcut)
if(Expression)
this(Type | Var)
target(Type | Var)
args(Type | Var , …)
MethodPat:
[ModifiersPat] TypePat [TypePat . ] IdPat ( TypePat | .., … ) [ throws ThrowsPat ]
ConstructorPat:
[ModifiersPat ] [TypePat . ] new ( TypePat | .. , …) [ throws ThrowsPat ]
FieldPat:
[ModifiersPat] TypePat [TypePat . ] IdPat
TypePat:
以下の「型の指定方法」を参照してください.

型の指定方法:インタータイプ宣言やポイントカット定義で使用

型の指定においても,単なるクラス名だけでなく,集合演算の一種が利用可能です.

まず,ワイルドカードとして,"*" があります.長さ0以上の文字列にマッチします.

// 戻り値として「すべての型」,メソッド名として set で始まるすべてのメソッド
pointcut setter(): execution(* Point.set*(..));

また,型名の後ろに "+" を付加すると,指定した型のすべてのサブクラスを含むようになります.

InputStream+  // InputStream を継承したクラスすべて

特定の型を取り除くには "!" を,共通集合・和集合をには "&&", "||" を使います.

(InputStream+ && !FileInputStream)  // InputStream とそのサブクラスで,ただし FileInputStream だけは除いた集合

一般形は以下のとおりです.

IdPat [ + ] [ [] … ]
! TypePat
TypePat && TypePat
TypePat || TypePat
( TypePat )

annotation の指定方法

注意: AspectJ 1.5M2 以降で,-1.5 オプションを指定して使用してください.

execution などのポイントカットでアノテーションを使いたくなったら,executionなどのメソッドパターンなどで先頭に @hoge とかを追加するだけです.メソッド宣言の場合と同じです.

execution(@logged * * *.*(..)) // @logged がついたメソッドにマッチ
execution(@foo @bar public void *.foo(..)) // @foo と @bar が両方必要

ただし,annotation も,単体で書くだけではありません.

!@hoge        // @hoge 以外の annotation にマッチ
@(Foo || Bar) // @Foo または @Bar にマッチ
@(org.xyz..*) // org.xyz とそのサブパッケージで定義された annotation にマッチ

なお,ユーザ定義の annotation を使いたい場合は,以下のようなファイルをやっぱり Java ファイルとして定義して,一緒にコンパイルするか,コンパイルしてクラスパスの通った場所に配置しておきます.詳細については Java での annotation の定義方法(参考: http://www-6.ibm.com/jp/developerworks/java/050128/j_j-annotate2.html )を調べてください.

public @interface logged {
}

annotation 指定の一般形は以下のとおりです.

AnnotationPattern := '!'? '@' AnnotationTypePattern AnnotationPattern* 
AnnotationTypePattern := FullyQualifiedName | '(' TypePattern ')'
FullyQualifiedName := JavaIdentifierCharacter+ ('.' JavaIdentifierCharacter+)*

その他,annotation については AspectJ 公式サイトの annotaiton に関する記述 (http://eclipse.org/aspectj/doc/ajdk15notebook/annotations.html )を参照してください.

その他,アスペクトに関するコーディング

アスペクトのフィールド,メソッド

アスペクトも自分自身のフィールド,メソッドを持つことができます. 定義方法は,クラスの中に,そのクラスのフィールドやメソッドを書く場合と同じです.static メンバー,static initializer も同様に記述することができます.

アスペクトがクラスと異なるのは,インスタンスが自動で生成されるというところです.

アスペクトのインスタンスへのアクセス

通常のアスペクトは,プログラム実行中,単一のインスタンスだけが存在し, aspectOf() クラスメソッドによってアクセスすることができます.

// アスペクトを定義
aspect LoggingAspect {
  void foo() { ... }
}
// アスペクトのインスタンスメソッドを呼び出す
LoggingAspect.aspectOf().foo(); 

また,perthis, percflow などを使っている場合,それぞれマッチしている Join Point に対して aspectOf(Object) メソッドを使って,アスペクトのインスタンスを取得します.


トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2006-10-23 (月) 12:06:21 (4407d)