chofutaroメモ

ソフトウェアエンジニアによるソフトウェアエンジニアのためのメモ書き

AspectJを使ってみる

AspectJを使ってみました。Javaを使った仕事にはAOPが欠かせないだろうという予想があったためです。

  • JDK6u24、NetBeans7.0β2
  • aspectj-1.6.10.jar

Toru TAKAHASHIさんのAspectJのウェブページの中にAspectJをどう使っていくかというページがあるのですが、そこに書かれていることは、仕事でJavaを使う場合のケースとして的を射ていると思いました。私はコンパイル時に(静的に)ウィービングすることだけをイメージしていたのですが、実行時にウィービングすることもできるんですね。これは活用の幅が広がりそうです。

AOPに関する用語は、AOPの用語にておさらいしておきました*1

NetBeans7.0β2/6.9.1用のAspectJをサポートするプラグインはないようだ

私が主に使っている開発ツールはNetBeansです。昨今の開発でIDEは欠かせないと考えているためで、自己啓発のために自宅でも使っています。
今回、AspectJNetBeans用プラグインをインストールしようとしましたが、NB7.0β2とは合わないためインストールできませんでした。NB6.9.1でもダメでした。

NetBeansAspectJをサポートしていたのはずっと昔のようで、今はプラグインが存在しないようです。

build.xmlを書き換えてコンパイルする

プラグインによる開発のサポートは諦めましたが、NetBeans主体でAspectJを使えないものか調査してみました。そこで判ったことは、build.xmlを書き換える手法をとっている方が多いということでした。
私もKdeveloper/Howto: AspectJ for Netbeansに記されている方法を真似てやってみたところjarファイルを作成することができました。これでなんとかウィービングまではNetBeansを使って開発できそうです。
build.xmlに追加したコードを載せておきます。

<!-- Add AspectJ tasks to Ant -->
    <!-- 出典:http://kdeveloper.com/aspectj-for-netbeans-howto/ -->

    <!-- aspectjtools.jarを格納するパスをaspectj.runtime.libに定義しました -->
    <taskdef classpath="${aspectj.runtime.lib}/aspectjtools.jar"
        resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

    <!-- Add an AspectJ build target -->
    <target name="aspectj">
        <echo level="info">--- aspectj (start) ---</echo>
        <iajc
            destdir="${build.classes.dir}"
            source="${javac.source}"
            target="${javac.target}"
            classpath="${javac.classpath}:${j2ee.platform.classpath}"
            deprecation="${javac.deprecation}"
            encoding="${source.encoding}"
            debug="${javac.debug}">
            <inpath>
                <pathelement location="${build.classes.dir}" />
            </inpath>
        </iajc>
    </target>

    <!-- Add the AspectJ target to your general project build -->
    <target name="-post-compile" depends="aspectj"></target>
</project>
runターゲットではウィービングされない

NetBeansを使って、ソースコードからウィービングされたクラスファイルを作成できるようになるまでに、私が大きく勘違いしていたことを報告しておきます。
勘違いしていたこと(判っていなかったこと)と言うのは、runターゲットが実行される前に、強制的にcompile(相当の)ターゲットが実行される(?)ということです。先にコンパイルしていれば、その時にできたファイルを使ってくれるものだと思っていました。
最初、Hello Worldをコーディングしたら即実行できると考えていたのですが、何度やっても実行結果がウィービングされたものになりません。
そこで初心に返り、以下に示すようなコマンドを手動で実行してみました。

java -cp %CLASSPATH%;build/classes メインクラス名
※CLASSPATHにはaspectjtools.jarを指定してあります。

結果、ウィービングされています。
どうやら、一度でもNetBeansで”主プロジェクトを実行”するとウィービングされていないクラスファイルになるようです。実行時に再コンパイルするのでしょうか、まだ仕組みはよく判っていません。現時点私は、Antの文法もろくに判っていないため今後の課題とします。

今回アノテーション方式を使いました

ちなみに、この時使ったアスペクトは以下のようになっています。Toru TAKAHASHIさんのAspectJにあるHello Worldをそのまま使わせていただきました。
アノテーション方式で記述してあります。その理由は単純で、NetBeansのエディタは、AspectJ言語で記述されたソースファイルをサポートしていないためです。

@Aspect
public class Trace {

    @Before("call (void HelloAspectJWorld.sayHello())")
    public void beforeAtSayHello() {
        System.out.println("[Before sayHello]");
    }

    @After("call (void HelloAspectJWorld.sayHello())")
    public void afterAtSayHello() {
        System.out.println("[After sayHello]");
    }
}

サンプルコード

所感

私の周りにはデバッグ用プリント文やデバッグのためのログを主体にデバッグする人が少なからずいます。この点の善し悪しはさておき、製品コードに(一時的にでも)デバッグ文を記載することは避けるべきである、という点は間違いないと思います。
AOP(特に実行時ウィービング)があればこの問題を解消できそうです。少なくとも、製品コードからトレース目的のデバッグ文を除去できます。製品コードに手を加えず、デバッグ文を組み込んだり抜いたりできるのはありがたい仕組みです。
また、今回は試してみませんでしたが、本来のAOP的活用として、フレームワークのバグやDB周りの例外をアプリケーション層とは全く別の場所(軸)で一括してキャッチできる、というのも魅力です。異常系処理は、AOPを使ってアプリケーション処理とは別の軸で一括処理することができれば、アプリケーション層を開発する人の手間がずいぶん減るのではないかと希望が膨らみます。

*1:とても判りやすかったです。