Spring 3.0 : そして AOP (2)

AOPは楽しいです。なんでだろう。ということで続きを。

2. @AspectJ

  • 織り込む処理:Adviceは処理のタイミングによって5種類ある
    • @Before: 実行前
    • @AfterReturning : 正常終了後
    • @AfterThrowing : 例外スロー後
    • @After : 実行後(正常、異常とわず)
    • @Around : 実行前後に処理を実行する場合(処理時間を計測する、など)
  • Adviceを宣言するには、メソッドに上のいずれかのアノテーションをつける
 @After("com.example.ExampleAspect.samplePointcut()")
publid void doAfter(){
..
}
    • アノテーションの引数にはポイントカットをしているする。"execute(* .."みたいに直接指定することも可能。
  • JoinPointを扱いたい場合は、アドバイスメソッドの最初に引数にProceedingJoinPointの引数を指定すればOK
  • args/returning/throwing などのパラメータをアノテーションに指定することにより、引数、戻り値、例外を処理することも可能
  • Adviceが実行される順番
    • 同じAspectクラスに複数定義されている場合、最初に定義されている方が @Beforeでは先に、@Afterでは後に実行される
    • 複数のAspectにまたがる場合は不定。だが、org.springframework.core.Orderedインタフェースを利用すれば制御カヌ
  • イントロダクション(AspectJで型間の宣言としてしられている)は、特定のオブジェクトにインタフェースとインタフェースで定義されるメソッドを定義することを可能にする。
  • Aspect はデフォルトではシングルトンでインスタンス化されるが、perThis/perTargetモデルにすることも可能。

3. スキーマXML)でアノテーション定義 はがっつり飛ばします。

4. どっちのAOPスタイルがいい?

5. 複数のAspectを利用する

6. プロキシの仕組み

  • Spring AOPはターゲットオブジェクトのプロキシを作成してAOPを実現している
  • インタフェースをひとつでも実装している場合はJDK ダイナミックプロキシ、そうでない場合はCGリビォ利用
  • 強制的にCGLIBを使うには、proxy-target-class="true"をaop:config/aop:aspectj-autoproxy に設定する
  • メソッド内で同じオブジェクトのメソッドを実行している場合、そのメソッドに設定されるアスペクトは実行されない
public class SimplePojo implements Pojo{
  public void foo(){
        this.bar();
  }
  
  public void bar(){
  }
    • fooにもbarにもアスペクトが織り込まれていて、fooを実行した場合、fooの実行時にはアスペクトも実行されるが、foo内のbarメソッドを実行するときは、直接barメソッドが実行されるだけ。
    • この現象を回避する方法は結構不細工なので、できれば自身のメソッドを呼び出さないようにリファクタリングする方がよい。
   public void foo() {
      // this works, but... gah!
      ((Pojo) AopContext.currentProxy()).bar();
   }
    • ただ、この現象はAspectJによるAOPではおこらない(プロキシベースじゃないから)

7. AspectJのプロキシオブジェクトをプログラム内から明示的に生成する

  • サンプルコード
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
factory.adAspect(SecurityManager.class);
factory.addAspect(usageTracker);
MyInterfaceType proxy = factory.getProxy();

8. AspectJをSpringアプリで使用する

  • ドメインオブジェクトのDIにAspectJを使用する場合、@Configurableでアノテートする。こうすると、newでインスタンスを作成した場合でもDIできる。
    • @Autowired/@Resourceを利用して自動的にBeanにDIすることもできる
    • @ConfigurableにdependencyCheck属性を設定すると、設定のバリデーションも可能。
    • この場合DIされるのは、初期化の後。もし、初期化の前にDIしたい場合は@Configurable(preConstruction=true)と設定する
  • @Configurableアノテーションが動くようにするためには、AspectJを利用するように設定する
    • antやmavenのビルド時の設定を変える
    • ロードタイム織り込みを利用する。
  • AnnotationBeanConfigurerAspectを利用するにも設定が必要。設定ファイルに以下を追加する。
<context:spring-configured />
  • @Configurableオブジェクトの単体テスト:AspectJを利用してコンパイルしていない場合は、そのま使用できる。AspectJを織り込んでコンパイルしている場合もそのまま単体テストできるけど、Springの警告を受けることになる

  • 複数のアプリケーションコンテキストを利用している場合、をどこに宣言し、spring-aspect.jarをどこに配置するか注意する。
    • 親アプリケーションコンテキストがあってそれを共有しているような場合、両方親の方におくべき。
    • 同じコンテナに複数のウェブアプリケーションをでプロイしているような場合、jarはそれぞれのWEB-INF/libに配備すべき。
  • @Transactional アノテーションというものもあるよ

最後LTWが残りました。