Last Updated : 2004/4/3
asato <asato@ncfreak.com>
[ TOP ]
アスペクト関連
これらアスペクトに関連のある事柄についての正確な情報源やサンプルコードが見つけられる場所としては The AspectJ Programming Guide を参照してください。特に、ここで扱っている事柄に関連のあるページとしては:
アスペクトの拡張 (extend)
アスペクトの継承を考える場合、1 つ注意する点があります: それは、クラスの継承と違ってアスペクトの継承では、抽象アスペクト のみ の継承が許されているということです。もし、具象アスペクト (abstract で宣言されていないアスペクト) を継承しようとすると、それはコンパイル時にエラーとなります:
public aspect ConcreteAspect { } public aspect ConcreteAspect extends ConcreteAspect { } // コンパイルエラー! // 抽象アスペクトでないアスペクトは // 継承できない public abstract aspect AbstractAspect { } public aspect ConcreteAspect extends AbstractAspect { } // OK
また、アスペクトは、具象アスペクト、抽象アスペクトにかかわらず、通常のクラスを継承したり、interface を実装することも許されています:
public interface Observer { } public aspect ConcreteAspect implements Observer { } // OK以下の節では、これらアスペクトの拡張に関連のある、より具体的なサンプルコードを紹介します。
アスペクトの拡張 - その 1 : アスペクトの継承
public abstract aspect AbstractAspect { }
public aspect ConcreteAspect extends AbstractAspect { }
アスペクトの拡張 - その 2 : アスペクトの継承
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public abstract aspect AbstractMainAspect { protected pointcut method() : call( void Main.method() ); }
public aspect MainAspect extends AbstractMainAspect { before() : method() { System.out.println("before"); } }
java> java -cp dest aoptest.Main before method
pointcut 再利用のその他のアプローチ
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect { pointcut method() : call( void Main.method() ); }
public aspect MyMainAspect { before() : MainAspect.method() { System.out.println("before"); } }
java> java -cp dest aoptest.Main before method
アスペクトの拡張 - その 3 : アスペクトの継承
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public abstract aspect AbstractMainAspect { protected abstract pointcut method(); before() : method() { System.out.println("before"); } }
public aspect MainAspect extends AbstractMainAspect { protected pointcut method() : call( void Main.method() ); }
java> java -cp dest aoptest.Main before Hello!
aspectOf()
aspectOf() - その 1
public class Main { public static void main(String[] args) { MainAspect aspect = MainAspect.aspectOf(); System.out.println( aspect ); } }
public aspect MainAspect { }
java> java -cp dest aoptest.Main aoptest.MainAspect@1a8c4e7抽象アスペクトに対しての aspectOf: 抽象アスペクトに対しての aspectOf() メソッドの呼び出しは、できません。コンパイル時にエラーとなります:
public class Main { public static void main(String[] args) { MainAspect aspect = MainAspect.aspectOf(); // コンパイルエラー System.out.println( aspect ); } }
public abstract aspect MainAspect { }
aspectOf() - その 2
public class Main { public static void main(String[] args) { Main main = new Main(); main.method(); MainAspect.aspectOf().setBeforeMessage("before before"); main.method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect { private String message = "before"; public void setBeforeMessage(String message) { this.message = message; } before() : call( void Main.method() ) { System.out.println(message); } }
java> java -cp dest aoptest.Main before method before before method
Aspect privilege
Aspect privilege - その 1 : private なフィールド
public class Main { private String str = "aaa"; public static void main(String[] args) { MainAspect.printString( new Main() ); } }
privileged aspect MainAspect { public static void printString(Main main) { System.out.println( main.str ); } }
java> java -cp dest aoptest.Main aaa
Aspect privilege - その 2 : private なメソッド
public class Main { public static void main(String[] args) { MainAspect.callMethod( new Main() ); } private void method() { System.out.println("method"); } }
privileged aspect MainAspect { public static void callMethod(Main main) { main.method(); } }
java> java -cp dest aoptest.Main method
Advice Precedence
Advice Precedence
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspectA { before() : call( void Main.method() ) { System.out.println("before - MainAspectA"); } }
public aspect MainAspectB { before() : call( void Main.method() ) { System.out.println("before - MainAspectB"); } }
public aspect MainAspect { declare precedence : MainAspectA, MainAspectB; }
java> java -cp dest aoptest.Main before - MainAspectA before - MainAspectB methodもし precedence 宣言の順番を入れ替えたとするなら:
public aspect MainAspect { declare precedence : MainAspectB, MainAspectA; }実行結果は:
java> java -cp dest aoptest.Main before - MainAspectB before - MainAspectA method
perthis
perthis - その 1
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect perthis( this(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08
perthis - その 2
public class Main { public Main() { System.out.println("Main()"); } public static void main(String[] args) { new Main(); } }
public aspect MainAspect perthis( this(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 Main()
perthis - その 3 : aspectOf
public class Main { public static void main(String[] args) { Main main = new Main(); System.out.println( MainAspect.aspectOf( main ) ); } }
public aspect MainAspect perthis( this(Main) ) { public MainAspect() { System.out.println("MainAspect() - " + this); } }
java> java -cp dest aoptest.Main MainAspect() - aoptest.MainAspect@1172e08 aoptest.MainAspect@1172e08
perthis - その 4
public class Main { public static void main(String[] args) { new Main(); new Main(); } }
public aspect MainAspect perthis( this(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aoptest.MainAspect@cf2c80
perthis - その 5
public class Main { public static void main(String[] args) { Main main = new Main(); main.method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect perthis( method() ) { private pointcut method() : execution( void Main.method() ); public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 method
perthis - その 6 : NoAspectBoundException
public class Main { public static void main(String[] args) { Main main = new Main(); System.out.println("aspectOf() - " + MainAspect.aspectOf(main) ); } public void method() { } }
public aspect MainAspect perthis( method() ) { private pointcut method() : execution( void Main.method() ); public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main Exception in thread "main" org.aspectj.lang.NoAspectBoundException at aoptest.MainAspect.aspectOf(MainAspect.java) at aoptest.Main.main(Main.java:12)
perthis - その 7 : perthis + execution
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect perthis( this(Main) ) { before() : execution( void Main.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main before method
perthis - その 8 : perthis + call
public class Main { // 変更なし public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect perthis( this(Main) ) { before() : call( void Main.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main method
perthis - その 9 : perthis + call
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { printMethod(); } private void printMethod() { System.out.println("method"); } }
public aspect MainAspect perthis( this(Main) ) { before() : call( void Main.printMethod() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main before method
perthis - その 10
public class YourMain { public void method() { System.out.println("YourMain - method"); } }
public class Main { public static void main(String[] args) { new YourMain().method(); } }
public aspect MainAspect perthis( this(Main) ) { before() : call( void YourMain.method() ) || execution( void YourMain.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main YourMain - method
perthis - その 11
public class Main { public static void main(String[] args) { Main main = new Main(); main.method(); main.method(); MainAspect.aspectOf(main).printCount(); } public void method() { System.out.println("method"); } }
public aspect MainAspect perthis( this(Main) ) { private int count; after() : execution( void Main.method() ){ count++; } public void printCount() { System.out.println("count: " + count); } }
java> java -cp dest aoptest.Main method method count: 2
perthis - その 12
public class Main { public static void main(String[] args) { Main main1 = new Main(); main1.method(); MainAspect.aspectOf(main1).printCount(); Main main2 = new Main(); main2.method(); MainAspect.aspectOf(main2).printCount(); } public void method() { System.out.println("method"); } }
public aspect MainAspect perthis( this(Main) ) { // 変更なし private int count; after() : execution( void Main.method() ){ count++; } public void printCount() { System.out.println("count: " + count); } }
java> java -cp dest aoptest.Main method count: 1 method count: 1
pertarget
pertarget - その 1
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect pertarget( this(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08
pertarget - その 2
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect pertarget( target(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08
pertarget - その 3
public class Main { public static void main(String[] args) { new Main(); new Main(); } }
public aspect MainAspect pertarget( this(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aoptest.MainAspect@cf2c80
pertarget - その 4
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect pertarget( target(Main) ) { before() : call( void Main.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main before method
pertarget - その 5
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect pertarget( this(Main) ) { before() : call( void Main.method() ) { System.out.println("before"); } }
// 横に長いので改行 (\ で改行場所を示している) しています java> java -cp dest aoptest.Main Exception in thread "main" java.lang.VerifyError: \ (class: aoptest/Main, method: methd signature: ()V) \ Unable to pop operand off an empty stack
pertarget - その 6
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect pertarget( target(Main) ) { before() : execution( void Main.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main before method
pertarget - その 7
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect pertarget( this(Main) ) { before() : execution( void Main.method() ) { System.out.println("before"); } }
// 横に長いので改行 (\ で改行場所を示している) しています java> java -cp dest aoptest.Main Exception in thread "main" java.lang.VerifyError: \ (class: aoptest/Main, method: methd signature: ()V) \ Unable to pop operand off an empty stack
pertarget - その 8 : pointcut = call
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect pertarget( method() ) { private pointcut method() : call( void Main.method() ); public MainAspect() { System.out.println(this); } }
// 横に長いので改行 (\ で改行場所を示している) しています java> java -cp dest aoptest.Main Exception in thread "main" java.lang.VerifyError: \ (class: aoptest/Main, method: mainsignature: ([Ljava/lang/String;)V) \ Unable to pop operand off an empty stack
pertarget - その 9 : pointcut = execution
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect pertarget( method() ) { private pointcut method() : execution( void Main.method() ); public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 method
percflow
percflow - その 1 : pointcut = this
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect percflow( this(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aoptest.MainAspect@6eb38a
percflow - その 2 : pointcut = target
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect percflow( target(Main) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aoptest.MainAspect@6eb38a
percflow - その 3 : : pointcut = call
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 method
percflow - その 4
public class Main { public static void main(String[] args) { Main main = new Main(); main.method(); main.method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 method aoptest.MainAspect@6eb38a method
percflow - その 5 : aspectOf()
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("aspectOf - " + MainAspect.aspectOf() ); System.out.println("method"); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aspectOf - aoptest.MainAspect@1172e08 method
percflow - その 6 : aspectOf()
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("aspectOf - " + MainAspect.aspectOf() ); printMethod(); } private void printMethod() { System.out.println("aspectOf - " + MainAspect.aspectOf() ); System.out.println("method"); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aspectOf - aoptest.MainAspect@1172e08 aspectOf - aoptest.MainAspect@1172e08 method
percflow - その 7 : aspectOf()
public class YourMain { public void method() { System.out.println("aspectOf - " + MainAspect.aspectOf() ); System.out.println("YourMain - method"); } }
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { new YourMain().method(); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aspectOf - aoptest.MainAspect@1172e08 YourMain - method
percflow - その 8 : NoAspectBoundException
public class Main { public static void main(String[] args) { new Main().method(); System.out.println("aspectOf - " + MainAspect.aspectOf() ); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 method Exception in thread "main" org.aspectj.lang.NoAspectBoundException at org.aspectj.runtime.internal.CFlowStack.peekInstance(CFlowStack.java:88) at aoptest.MainAspect.aspectOf(MainAspect.java) at aoptest.Main.main(Main.java:12)
percflow - その 9 :
public abstract class AbstractMain { public abstract void method(); }
public class Main extends AbstractMain { public static void main(String[] args) { AbstractMain main = new Main(); main.method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflow( execution( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@cf2c80 method
percflow - その 10 :
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
public aspect MainMethodAspect { before() : call( void Main.method() ) { System.out.println("before - call"); } before() : execution( void Main.method() ) { System.out.println("before - execution"); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 before - call before - execution method
percflow - その 11 : インスタンスはいつ生成されるか?
public class Main { // 変更なし public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflow( execution( void Main.method() ) ) { public MainAspect() { System.out.println(this); } }
public aspect MainMethodAspect { // 変更なし before() : call( void Main.method() ) { System.out.println("before - call"); } before() : execution( void Main.method() ) { System.out.println("before - execution"); } }
java> java -cp dest aoptest.Main before - call aoptest.MainAspect@cf2c80 before - execution method
percflow - その 12 : advice の適用範囲 - その 1
public class YourMain { public void method() { System.out.println("YourMain - method"); } }
public class Main { public static void main(String[] args) { new YourMain().method(); } public void method() { } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } before() : call( void YourMain.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main YourMain - methodもし percflow を使用していないとしたら:
public aspect MainAspect { public MainAspect() { System.out.println(this); } before() : call( void YourMain.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 before YourMain - method
percflow - その 13 : advice の適用範囲 - その 2
public class YourMain { public void method() { System.out.println("YourMain - method"); } }
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { new YourMain().method(); } }
public aspect MainAspect percflow( call( void Main.method() ) ) { public MainAspect() { System.out.println(this); } before() : call( void YourMain.method() ) { System.out.println("before"); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 before YourMain - method
percflowbelow
percflowbelow - その 1 : pointcut = this
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect percflowbelow( this( Main ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aoptest.MainAspect@6eb38a
percflowbelow - その 2 : pointcut = target
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect percflowbelow( target( Main ) ) { public MainAspect() { System.out.println(this); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@1172e08 aoptest.MainAspect@6eb38a
percflowbelow - その 3 :
public class Main { public static void main(String[] args) { new Main(); } }
public aspect MainAspect percflowbelow( target( Main ) ) { public MainAspect() { System.out.println(this); } before() : target(Main) { System.out.println(thisJoinPoint); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@4a5ab2 execution(aoptest.Main()) aoptest.MainAspect@e53108percflow との比較:
public aspect MainAspect percflow( target( Main ) ) { public MainAspect() { System.out.println(this); } before() : target(Main) { System.out.println(thisJoinPoint); } }
java> java -cp dest aoptest.Main aoptest.MainAspect@12b6651 initialization(aj.Main()) aoptest.MainAspect@e53108 execution(aj.Main())
percflowbelow - その 4 :
public class Main { public static void main(String[] args) { new Main().method(); } public void method() { System.out.println("method"); } }
public aspect MainAspect percflowbelow( call( void Main.method() ) ) { before() : target(Main) { System.out.println(thisJoinPoint); } }
java> java -cp dest aoptest.Main execution(void aoptest.Main.method()) methodpercflow との比較:
public aspect MainAspect percflow( call( void Main.method() ) ) { before() : target(Main) { System.out.println(thisJoinPoint); } }
java> java -cp dest aoptest.Main call(void aoptest.Main.method()) execution(void aoptest.Main.method()) method
アスペクトのインスタンス化
通常、アスペクトのインスタンス化は new を使ってはできませんが、もし、アスペクトが privileged として宣言されているのであれば、アスペクトをインスタンス化することはできます(しかし、これはバグの可能性があります):
public class Main { public static void main(String[] args) { System.out.println("aspectOf() : " + InnerAspect.aspectOf() ); System.out.println("newInstance(): " + InnerAspect.newInstance() ); System.out.println("newInstance(): " + InnerAspect.newInstance() ); } privileged private static aspect InnerAspect { public static InnerAspect newInstance() { return new InnerAspect(); } } }
aspectOf() : aoptest.Main$InnerAspect@1c78e57 newInstance(): aoptest.Main$InnerAspect@5224ee newInstance(): aoptest.Main$InnerAspect@f6a746しかし、問題点は advice 内での this は aspectOf() で取得できるインスタンスにバインドされることです。たとえば、一つのインスタンスに一つのアスペクトを割り当てたいようなケースを考えて見てください:
public class MyClass { public void method() { System.out.println("MyClass.method()"); } }
public class Main { public static void main(String[] args) { MyClass my1 = new MyClass(); MyClass my2 = new MyClass(); InnerAspect.newInstance(my1); InnerAspect.newInstance(my2); my1.method(); } privileged private static aspect InnerAspect { private MyClass my; public static InnerAspect newInstance(MyClass my) { InnerAspect instance = new InnerAspect(); instance.my = my; return instance; } before() : call( void MyClass.method() ) { System.out.println(this + " - " + my); } } }実行結果は:
aoptest.Main$InnerAspect@5224ee - null MyClass.method()一つの解決策は:
public class Main { public static void main(String[] args) { MyClass my1 = new MyClass(); MyClass my2 = new MyClass(); System.out.println("my1: " + my1); System.out.println("my2: " + my2); System.out.println(); System.out.println( InnerAspect.newInstance(my1) ); System.out.println( InnerAspect.newInstance(my2) ); System.out.println(); my1.method(); } privileged private static aspect InnerAspect { private MyClass my; public static InnerAspect newInstance(MyClass my) { InnerAspect instance = new InnerAspect(); instance.my = my; return instance; } before() : call( void MyClass.method() ) { System.out.println(this + " - " + my); } } privileged private static aspect InnerAspectAspect { private static List aspects = new ArrayList(); InnerAspect around() : call(InnerAspect InnerAspect.newInstance(MyClass) ) { InnerAspect instance = proceed(); aspects.add( instance ); return instance; } void around(InnerAspect instance) : target(instance) && adviceexecution() && !within(InnerAspectAspect) { for(Iterator itr = aspects.iterator() ; itr.hasNext(); ) { proceed( (InnerAspect)itr.next() ); } } } }実行結果は:
my1: aoptest.MyClass@1ac04e8 my2: aoptest.MyClass@765291 aoptest.Main$InnerAspect@1004901 aoptest.Main$InnerAspect@1b90b39 aoptest.Main$InnerAspect@1004901 - aoptest.MyClass@1ac04e8 aoptest.Main$InnerAspect@1b90b39 - aoptest.MyClass@765291 MyClass.method()ただし、around adivce を扱う場合(たとえば InnerAspect に around adivce がある場合)は、もう少し複雑になります。 [ TOP ]
更新履歴
todo
private static aspect ActionListenerAspect implements ActionListener pertarget( newMenuButton() ) { private JButton button; private pointcut newMenuButton() : this(MenuButtonWrapper); after(JButton button) : execution(MenuButtonWrapper.new(JButton)) && args(button) { System.out.println(button); // this.button = button; } public void actionPerformed(ActionEvent e) { System.out.println(e); } }