DIxAOPの機能の概要を見てみましょう!
まず、AOPって何でしょう?
これはSpring独自の技術というより、AspectJなどの他のフレームワークが提供している機能です。
具体的には、以下の記事を見てみてください。
【Springの役割】
AOPはSpringの機能ではありません。
では、Springは何をしてくれるんでしょう?
実は、AOPの処理をAspectJなどで実現しようとすると、いろいろな準備やコードを書かないといけないんです。
上記の記事(AOPとは? )を見るとinvokeがメインなので、本当はそのコードだけを書きたいですよね?
でも、他にもいろいろやらないといけないらしいです。
Springは上のコードを書くのと、織り込む場所を設定ファイルを書くだけでいいのです。
それがDIxAOPなのです。
【SpringAOPで必要なライブラリ】
以下のライブラリをクラスパスに入れておけばとりあえず動作すると思います。
(使い方によっては不要なものもありますが。。)
・asm-all.jar
・aspectjrt.jar
・aspectjweaver.jar
・cglib-nodep.jar
※Googleで検索すれば簡単にダウンロードできます!
【Spring設定ファイルの記述例】
<bean name="logging" class="aop.LoggingInterceptor" /> <aop:config> <aop:advisor pointcut="execution(* org.apache.struts.action.Action+.execute(..))" advice-ref="logging" /> </aop:config>
aop:という名前空間で設定します。
織り込む処理は、beanとして設定しておきます。
それをadvice-refに設定します。
織り込む場所は、pointcutで指定しますが、その記述方法が味噌です。
ここでは、executionという書き方で書いているのでそれについてみていきます。
記法は、execution(返り値の型 パッケージ名+クラス名+メソッド名(引数)) 。
上記の場合は、
execution(* org.apache.struts.action.Action+.execute(..))
返り値の型をワイルドカード指定にし、
パッケージ名はフルでそのまま記述。
クラス名は、Actionの派生クラスを指定しています。
親クラスに+をつけるとその派生クラスを示します。
メソッド名は、executeをそのまま指定しています。
引数は、..で、なんでもよいことを示す記号です。
【SpringデフォルトのAOPの注意点】
便利になったAOPですが、注意点もいくつかあります!
ただし、これはデフォルトの注意点です。
そもそもSpringはinterfaceをimplementsすることを強要するのがデフォルトです。
以下にそれに伴う注意点を記述しておきます。
(ただし、もっと自由に使う方法をその後に記述します。)
・Springの設定ファイルに記述したbeanに対してしか織り込みができません。
これは、Springの設計方針なので、それほど驚くことではないかと思います。
(自分でnewしたオブジェクトには適用されません)
・beanのメソッドの中でもpublicのメソッドのみです。
・AOPは、ポイントカットで指定されたメソッドなどの呼び出し場所に織り込まれます。
ですので、上記の注意点とあわせると以下のようになります。
メソッドAに織り込みをしても、beanで管理していないクラスの中でA()を呼び出した場合、その位置には
織り込まれません。
・Springファイルで設定されたbeanのメソッドを呼び出している箇所にしかポイントカットを指定できません。
・executionで、あるクラス名を含めてメソッド名を指定した場合、親クラスに記述されたメソッドは
織り込みされません。(これは記述の注意です。親のメソッドは別途指定すればいいかと思います)
・リフレクションで呼ばれているメソッド箇所には、どうも織り込みできないっぽいです。
(正式な文書では未確認ですが、実験した感じではそうでした)
・Aメソッドに織り込みをした場合、this.A()に対しては織り込まれないっぽいです。
つまり、クラス内から呼ばれるケースでは織り込まれないっぽいです。
これは、織り込みによる予期せぬ変な動きなどを防ぐ意味で、安全性のためかと思います。
・織り込みの設定は複数できるので以下のように同じ場所に違う織り込みをしたときにどういう順番になるか?
は注意点です。
<aop:advisor pointcut="execution(* org.apache.struts.action.Action+.execute(..))"
advice-ref="logging" />
<aop:advisor pointcut="execution(* org.apache.struts.action.Action+.execute(..))"
advice-ref="stopwatch" />
もしかしたら適用順のルールがあるかもしれませんが、自分はまだ調べ切れていません。(すみません)
とりあえず、重ならないように設定ファイルを記述するか、重なっても大丈夫なクラスを織り込むのがいいかと。
【自由に使う方法】
上記のようにデフォルトで使用するとかなり制限がありますが、インターフェースを強要するということでは意味があるかと思います。
インターフェースを使用しなければ変更がしにくくなるからです。
しかし、場合によってはインターフェースを使用しないものにもAOPを織り込みたくなると思います。
このインターフェースを使用しなくてもよくするのが、以下の記述です。<aop:config proxy-target-class="true">
デフォルトではfalseです。
trueにすることで、AOPの織り込み先を、interfaceではなくclassに変更します。
これだけで、インターフェースを使用しないクラスに対してAOPが使えるようになります。
内部では、この設定によりCGLIBというライブラリを使用するようになるようです。
※注意点
eclipseを使用している場合、相性が悪いのかエラーが出ます。
「ブレークポイントを再現できません。欠落した行番号情報。」みたいなエラーです。
原因は分かりませんが、特に問題ありませんでした。ですので無視しても良さそうな気がします。
【使いどころは?】
共通的な処理で使用するのがいいかと思います。
つまり、ルール化して開発者みんなにすぐにどこで使用しているかが分かるような箇所です。
というのは、AOPはどこにでも織り込めるため、コードを見るだけで処理を追えなくなるからです。
やたら滅多に使用するとメンテが大変になりますので注意です。
よく言われるのは、WEBのリクエストのパラメタのログをとるなどですかね。
ログなどは不具合がおきたときだけ商用でデバッグログをとったりしますが、
AOPならすぐに、どんな箇所にも織り込めます。
それに設定一つではずすこともできます!
参考:
・Springに付属のAOPサンプルのログトレースを動かすには?
JavaプロキシとCGLIBプロキシ