目次
対象ソースファイルソースはこんな感じ。public class HelloAspectWorld? { public static void main(String [] args){ new HelloAspectWorld?().sayhello(); } void sayhello(){ System.out.println("Hello World"); } }ajcで作ったクラスをjodeで戻してみた。 あとでバイトコードを出しているが、そっちから判断できる通りのソースになってる。 public class HelloAspectWorld? { public static void main(String[] args) { HelloAspectWorld? helloaspectworld = new HelloAspectWorld?(); try { Trace.aspectOf().ajc$before$Trace$1$705b637b(); helloaspectworld.sayhello(); } catch (Throwable throwable) { // ここの処理は確かにbytecode上、合ってそうだが、何でこうなってるのか意味不明 Trace.aspectOf().ajc$after$Trace$2$705b637b(); throw throwable; } Trace.aspectOf().ajc$after$Trace$2$705b637b(); } void sayhello() { System.out.println("Hello World"); } } で、Aspectのクラスはこんな感じ。 aspect Trace { pointcut atSayHello(): call(void HelloAspectWorld?.sayhello()); before(): atSayHello() { System.out.println("[Before sayhello()]"); } after(): atSayHello() { System.out.println("[After sayhello()]"); } }こっちもjodeで戻して?みた。 jodeの逆コンパイルコードで、生成ミスってる所は適当に修正済 こちらはテストコードを試した時は気にならなかったが、Aspectはクラスロードの時点で、Aspectのインスタンスを singletonで用意してるコードになっているようだ。
import org.aspectj.lang.NoAspectBoundException?; public class Trace { private static Throwable ajc$initFailureCause; public static Trace ajc$perSingletonInstance; static { try { ajc$postClinit(); } catch (Throwable throwable) { ajc$initFailureCause = throwable; } } Trace() { /* empty */ } public void ajc$before$Trace$1$705b637b() { System.out.println("[Before sayhello()]"); } public void ajc$after$Trace$2$705b637b() { System.out.println("[After sayhello()]"); } public static Trace aspectOf() { Trace trace = ajc$perSingletonInstance; if (trace != null) return trace; throw new NoAspectBoundException?("Trace", ajc$initFailureCause); } public static boolean hasAspect() { if (ajc$perSingletonInstance != null) return true; return false; } private static void ajc$postClinit() { ajc$perSingletonInstance = new Trace(); } }
コンパイルと実行コンパイルは相当微妙で、こんな感じ。 AspectJ コンパイラは 1.2版で配布されている。コンパイル時にCLASSPATHに同梱の aspectjrt.jarが必須。 aspectjrt.jarが無いと、ajc自体が動かない。 % ajc *.javaちなみに ajcもそうだが、配布パッケージ内のコマンドはshell scriptで実体は aspectjtools.jarに あるクラスのpublic static void main()を実行するようになってる。ajcの場合はこれ。 "$JAVA_HOME/bin/java" -classpath" $ASPECTJ_HOME/lib/aspectjtools.jar:$JAVA_HOME/lib/tools.jar:$CLASSPATH" -Xmx64M org.aspectj.tools.ajc.Main "$@"注意:何でそうしてるのか分からないが、Aspectのファイルのsuffixは.javaで無いとajcのコンパイル対象にならないようだ。 バイトコードを見てみるどうも違うっぽい気がしてきたので、後で調査。 ちなみにバイトコードは javap -c じゃなく、D-Javaの出力。 まずはajcで作成した物。 Major version: 46 Minor version: 0 public synchronized class HelloAspectWorld? extends Object { Method public void <init>() >> max_stack=1, max_locals=1 << 0 aload_0 1 invokenonvirtual #9 <Method Object.<init>():void> 4 return Local variable table: start length slot 0 5 0 this:HelloAspectWorld? Line number table: pc line 0 6 Method public static void main(String[]) >> max_stack=2, max_locals=2 << 0 new #2 <Class HelloAspectWorld?> 3 dup 4 invokenonvirtual #16 <Method HelloAspectWorld?.<init>():void> 7 invokestatic #43 <Method Trace.aspectOf():Trace> 10 invokevirtual #46 <Method Trace.ajc$before$Trace$1$705b637b():void> 13 invokevirtual #19 <Method HelloAspectWorld?.sayhello():void> 16 goto 28 19 astore_1 20 invokestatic #43 <Method Trace.aspectOf():Trace> 23 invokevirtual #49 <Method Trace.ajc$after$Trace$2$705b637b():void> 26 aload_1 27 athrow 28 nop 29 invokestatic #43 <Method Trace.aspectOf():Trace> 32 invokevirtual #49 <Method Trace.ajc$after$Trace$2$705b637b():void> 35 nop 36 return Exception table: from to target type 7 16 19 <Class Throwable> Local variable table: start length slot 0 37 0 args:String[] Line number table: pc line 0 9 36 10 Method void sayhello() >> max_stack=2, max_locals=1 << 0 getstatic #27 <Field System.out:PrintStream?> 3 ldc #29 <String "Hello World"> 5 invokevirtual #35 <Method PrintStream?.println(String):void> 8 return Local variable table: start length slot 0 9 0 this:HelloAspectWorld? Line number table: pc line 0 13 8 14 }んで次は javacで作成した物 Major version: 46 Minor version: 0 public synchronized class HelloAspectWorld? extends Object { Method public void <init>() >> max_stack=1, max_locals=1 << 0 aload_0 1 invokenonvirtual #1 <Method Object.<init>():void> 4 return Line number table: pc line 0 6 Method public static void main(String[]) >> max_stack=2, max_locals=1 << 0 new #2 <Class HelloAspectWorld?> 3 dup 4 invokenonvirtual #3 <Method HelloAspectWorld?.<init>():void> 7 invokevirtual #4 <Method HelloAspectWorld?.sayhello():void> 10 return Line number table: pc line 0 9 10 10 Method void sayhello() >> max_stack=2, max_locals=1 << 0 getstatic #5 <Field System.out:PrintStream?> 3 ldc #6 <String "Hello World"> 5 invokevirtual #7 <Method PrintStream?.println(String):void> 8 return Line number table: pc line 0 13 8 14 } |