Spring AOPメモ

Spring AOPの機能を探るべく、公式ドキュメント(8. Aspect Oriented Programming with Spring)を参考に色々試してみました。その時に気がついた点をいくつかまとめてみます。(@Transactionalアノテーションは検証していません)

@Aspectを付けたクラスをSpringに管理させる

@Aspectを付けてもSpringがBeanとして認識していないとAOPが機能しません。スキーマAOPの設定を書いたり、@Aspectに加えて@Componentまで書くのは面倒。そのような場合には、component-scanの設定に以下のようなフィルタを加えるとよいです。

<context:component-scan base-package="com.imarket.tdnet.spider" >
	<!-- @Aspectをスキャン -->
	<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" />
</context:component-scan>

参考にしたサイト
minokubaの日記 7.2 @AspectJ support
第8章に限らず和訳が充実しており、大変参考になるブログです。

publicメソッドしか織り込めない?

どこで読んだのか忘れたのですが、Spring AOPではpublicメソッドが対象になると思っていました。ドキュメントでは以下の様な記述があります。

Note
Due to the proxy-based nature of Spring's AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn't applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!

protectedメソッドに織り込むのはJDKのプロキシでは無理、CGLIBのプロキシでは技術的に可能だけどすべきではない、というところでしょうか。試しに、

<aop:aspectj-autoproxy proxy-target-class="true"/>

という設定を追加してCGLIBのプロキシを有効にしてみたのですが、protectedメソッドにアスペクトは織り込まれませんでした。設定が間違っているのかな?
代わりにと言ったらなんですが、"bean(Bean名)"でポイントカットを指定するとprotectedメソッドにも織り込めました。

AspectJを使う場合の設定について

SpringでAspectJを使う場合の設定ですが、ドキュメント通りにやらなくても動いてるように見えるんですよね。例えば、って付けても付けなくても特に結果が変わらなかったりとか。。
手元で試してみた結果をまとめると以下のうような感じでした。

  • javaagent:に渡すjarはaspectjweaver.jarでもspring-instrument.jarでもどちらも同じだった(AepceJのクラスが全部入り?のaspectjtools.jarはマニフェストファイルでPremain-Classが指定されてないせいか駄目)
  • コンパイル時に or の設定を書くと@Configurableが有効に
  • と書かなくてもMETA-INF/aop.xmlの設定があればアスペクトが織り込まれる
  • と書いた場合、-javaagent:にspring-instrument.jarを渡さないとエラー
  • aop.xmlタグがない、またはタグが1つもない場合、全てのクラスに織り込まれる

あと、@Configurableを付けたクラスにpublicメソッドがあるとエラーが出ます。エラーメッセージ読んでも理由がさっぱり分からず。

java.lang.IllegalStateException: Post-processor tried to replace bean instance of type [com.imarket.tdnet.spider.factory.Test2] with (proxy) object of type [$Proxy28] - not supported for aspect-configured classes!
	at org.springframework.beans.factory.wiring.BeanConfigurerSupport.checkExposedObject(BeanConfigurerSupport.java:170) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE]
	at org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:142) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE]
	at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59) ~[spring-aspects-3.1.1.RELEASE.jar:3.1.1.RELEASE]
	at org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:89) ~[spring-aspects-3.1.1.RELEASE.jar:3.1.1.RELEASE]

ちなみに、コマンドラインから-javaagent:を渡す場合は-jarの前に書く必要があります。

java -javaagent:lib/aspectjweaver.jar -jar myapp.jar
 

とりあえずこんなところでしょうか。そのうち@Transactionalアノテーションも検証してみたいですね。