Spring Framework 入門記 AOPその13 AutoProxyCreator
今回は「5.7. Creating AOP proxies programmatically with the ProxyFactory」です.ProxyFactoryを使ってAOP Proxyを作る,と.ふむふむ.
な,なんですとぉー? 昨日どこにも書いてなーい! って文句を書いたProxyFactoryの使い方が,ちゃんと書いてあるではないですか! 与太話はいいから説明してくれよって書いたことが,ちゃんと説明してあるではないですか! ...心より恥じる.
うー,なんてこった.そういうことなら5.7じゃなくて5.6.3にしてくれよぉ.それなら気づいたのにぃ.しくしくしく.やっぱり少しは先読みしておかなきゃダメか.無念だ.
しょーがねー,軽く読んでスキップだ.AOP Proxyを作るには,ProxyFactory
を使って,addInterceptor(MethidInterceptor)
やaddAdvisor(Advisor)
とかでWeavingするAspectを指定して,最後にgetProxy()
でAOP Proxyを取り出せばよいわけね.オッケー,昨日調べたとおりだよ.もういいよ.バイバイ〜.
ということで,「5.8. Manipulating advised objects」に進みます.
ProxyFactoryで作成されたAOP Proxyは,Adviced
というinterface
をimplements
しているとのこと.ふむふむ.このinterface
のメソッドを使うことで,新たにAspect(Interceptor/Advisor)を追加したり削除したりできるそうです.ふーん.
あまり使う機会なさそうだなぁ.まぁ,必要に迫られたときにはそういうこともできるとだけ覚えておくことにして,スキップしちゃいましょう.心より恥じる.
本日はこれで終わり,というのもちゃんちゃらおかしいので,次は「5.9. Using the "autoproxy" facility」に進みます.
これまで,AOP ProxyはProxyFactoryBean
などを使って明示的に作成してきたわけですが,実はもっとお手軽な方法があったようです.それが autoproxy というもので,コンテナがロードされたときに自動的にAOP Proxyを作成してくれるとのこと.いいねぇ.
なお,この仕掛けはBeanPostProcessor
を使って構築されているらしいです.このinterface
,「Chapter 3. Beans and the ApplicationContext」にチラッとでてきていたのですが,ろくな解説がなかったので気づかなかったことにしていたんですよね.心より恥じる.
どうやらこのBeanPostProcessor
のメソッドは,コンテナがBeanのインスタンスを作るたびにコールバックされるので,そこでBeanをいろいろと細工できるということらしいです.そこでProxyFactory
に食わせてあげるってわけなのでしょう.なるほど.
それでその,autoproxyを使うには,大雑把に言って二つの方法があるとのこと.
むむ,メタデータ... あの.NETで使われている,あれのこと? JDK1.5で導入される,あれのこと? っていうよりむしろXDocletのあれのこと?
興味は尽きませんが,とりあえず順番に行きましょう.
まずはautoproxy creatorを使う方法です.autoproxy creatorの実装として,二つのクラスが用意されているようです.
BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
まずはBeanNameAutoProxyCreator
について.
これは名前のとおり,指定された名前(<bean>
要素のid
属性やname
属性)のBeanに対してAspectをWeavingしてくれるautoproxy creatorです.ProxyFactoryBean
同様,interceptorNames
というプロパティがあり,適用するAspect(Interceptor/Advisor)を指定することができます.なるほどなるほど.簡単に使えそう.
次にDefaultAdvisorAutoProxyCreator
ですが,こちらはもっとeXtreamでpowerfulなautoproxy creatorとのことです.そのうえautomagicallyなんだって.automaticallyじゃなくて.ワクワク?
どういうことかというと,BeanにマッチするPointcutがあれば,それを片っ端から適用してくれるらしいです.そういえばSpringのPointcutは,ClassFilter
とMethodMatcher
から構成されていました.なるほど,こういう使い方をするためだったわけですか.ProxyFactoryBean
を使っていたときは,ClassFilter
なんて冗長な感じがしたものですが,これで納得出来ました.
なお,DefaultAdvisorProxyCreator
で適用できるのはAdvisorだけで,Interceptorではダメとのこと.InterceptorはAround AdviceですからPointcutを持っていないためでしょうね.そういう場合は,DefaultPointcutAdvisor
などを使ってPointcutと組み合わせてあげれば大丈夫なはず.
autoproxy creatorを使うと,BeanとAspectは,AspectJに近い関係になりますね.BeanはAspectの事はまったく知らなくて,Aspectの側が対象となるBeanをを知っているというわけなので.ということで,「Compontn配下のAspect」で書いたようなことが気になります.
その一つ,Aspectが適用される順番ですが,SpringではOrdered
というinterface
を用意しています.これは,「AOPその10 Introduction Advice」でまったく無意味な使い方をしたものなのですが,実はDefaultPointcutAdvisor
など,たいていのAdvisorはこれをimplements
しています.このinterface
はgetOrder()
というメソッドを持っていて,これでAdviceに適用する順序を持たせることができるということだと思われます.AspectJのdeclare precedence
と同じ考え方ですね.うーん.
それからAspectがどのBeanに適用されるかについては,実行時のログで確認するしかなさそうです.無念だ.あ,もしかして世間で話題になっているSpring UI for Eclipseとか使うとそういうことも分かっちゃうのかなぁ? それならいいかも.インストールもしてないんだよな.心より恥じる.
さてさて,例によってつまらないものを作ってみましょう.役に立たなくてもいいもんね.どうせ日記だしぃ.
ということで,今回はDefaultAdvisorProxyCreator
を使ってみます.あらかじめ言い訳を済ませてあるので,遠慮なくDebugInterceptor
を使いましょう.
まずはターゲットになるクラスを作成します.
package study; public class Foo { public void one() { System.out.println("one"); } public void two() { System.out.println("two"); } public void three() { System.out.println("three"); } }
申し訳ないくらいに役立たずのメソッドが3つも.
次に,定義ファイルを用意します.
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean> <bean id="debugAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="pattern"><value>study\..*\.[a-z]{3}</value></property> <property name="advice"> <bean class="org.springframework.aop.interceptor.DebugInterceptor"/> </property> </bean> <bean id="foo" class="study.Foo"> </bean>
正規表現(もろパクリ)で指定したパターンにマッチすればDebugInterdeptor
を適用してくれるはず.
それから,RegexpMethodPointcutAdvisor
のパターンがクラスの完全限定名込みでマッチングを行う理由もわかりますね.複数のクラスにまたがって適用する場合に一気に記述できます.
ということで,Foo
のメソッドを順次呼び出すようなクラスを作成して,実行!!!
- Pre-instantiating singletons in factory [org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans [propertyPlaceholderConfigurer,customEditorConfigurer,autoProxyCreator,debugAdvisor,foo]; Root of BeanFactory hierarchy] - Creating shared instance of singleton bean 'foo' - Candidate Advice [org.springframework.aop.support.RegexpMethodPointcutAdvisor@1bcdbf6] accepted for class [study.Foo] - Creating implicit proxy for bean 'foo' with 0 common interceptors and 1 specific interceptors - Bean 'context' instantiated via constructor [public org.springframework.context.support.ClassPathXmlApplicationContext(java.lang.String[]) throws org.springframework.beans.BeansException] Debug interceptor: count=1 invocation=[Invocation: method=[public void study.Foo.one()] args=[Ljava.lang.Object;@6782a9] target is of class study.Foo] one Debug interceptor: next returned Debug interceptor: count=2 invocation=[Invocation: method=[public void study.Foo.two()] args=[Ljava.lang.Object;@6782a9] target is of class study.Foo] two Debug interceptor: next returned three
となって,見事にone()
およびtwo()
にはDebugInterceptor
が適用されました.一応Foo
にRegexpMethodPointcutAdvisor
が適用されたことがメッセージから伺えますが,Advisorのインスタンスが複数あると何が適用されたか分からなさそうです.無念だ.
個人的にはS2的にbean(S2ではcomponent)の下にaspectを定義するほうが明示的で好みなのですが,Springではautoproxy creatorを使うほうが使い勝手がよいのかもしれません.無念だ.
ということで,今日はここまで.次回は残りのメタデータを学習します.