椅子が壊れた?

自宅で使っている椅子が壊れてしまったっぽい.背もたれが一番手前(垂直より手前)まで傾いて戻らないのです.超前傾姿勢で日記付けてます.無念だ.
このまま直せないようだったら新しい椅子を購入しなくてはなりません.えっ? 新しい椅子を購入したいからってわざと壊したわけじゃないですよっ.朝起きたら壊れてたんですよぉ.本当です,ほんと.
で,新たに買うとしたら何がいいか.定番のアーロンチェアは以前ショップで座ったときの印象があまりよくなかったんですよね.
ということで,注目はスチールケースLeap HD.以前購入した雑誌でアーロンチェアイプシロンなどを押さえてNo.1の評価を得ていたのです.秋葉原ヤマギワリビナ本館に置いてあるらしいので,金曜日に時間があったら行ってみるべし.
もう一つ気になるのは枕で有名なテンピュールシンクロン7.何せ座面や背もたれがあの枕と同じテンピュール素材.しかも左右に分割された背もたれのクッションが妖しい魅力を放っています.ちなみに上位モデルのグラールエグゼクティブは,ニューヨーク近代美術館(だったかな?)の所蔵品になっているとか.以前東急ハンズで試したときには思い通りにセッティングができなかったので,今度まじめにチェックしてこよう.
さて,問題は予算... 無念だ.

お仕事スタイル

なんか,昨日と違ってまた寒くなっちゃいましたね.着れるうちに着ておこうということで,DIOR HOMMEのブルゾンです.
でも,今夜は雨なの? 大丈夫か?

「日本発の「世界最先端」,オープンソース軽量コンテナに熱い視線」

日経BPIT Proに「Seasarのからさわぎ@東京」のレポートが掲載されています.単なるレポートではなく,IoCおよびAOPを簡潔にうまくまとめた解説ですね.
この著者の方もからさわぎにいらっしゃっていたのかぁ.自分はタバコを吸わないもので,喫煙所で盛り上がっていたことも他の方の日記で知った次第.自分もお話したかったなぁ.無念だ.

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というinterfaceimplementsしているとのこと.ふむふむ.この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は,ClassFilterMethodMatcherから構成されていました.なるほど,こういう使い方をするためだったわけですか.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しています.このinterfacegetOrder()というメソッドを持っていて,これでAdviceに適用する順序を持たせることができるということだと思われます.AspectJdeclare 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が適用されました.一応FooRegexpMethodPointcutAdvisorが適用されたことがメッセージから伺えますが,Advisorのインスタンスが複数あると何が適用されたか分からなさそうです.無念だ.


個人的にはS2的にbean(S2ではcomponent)の下にaspectを定義するほうが明示的で好みなのですが,Springではautoproxy creatorを使うほうが使い勝手がよいのかもしれません.無念だ.
ということで,今日はここまで.次回は残りのメタデータを学習します.

ThrowsInterceptor

使えないSpringのThrwosAdviceのかわりに,ひがさんが素敵なThrowsInterceptorを作ってくださいました.
SpringのThrwosAdviceがどうして使えないのかというと,問題点が二つあるのです.

  • メソッドの再実行ができない.

正確に言えばできなくはないのですが,それはjava.lang.reflect.Methodを通じて呼び出すことができるだけです.この場合,ターゲットといま例外を処理しているThrwosAdviceとの間に挟まっているAdvice(Interceptor)は実行されないはず.例えば,トランザクションAdviceがあって,その外側にデッドロックが発生した場合に限りリトライを行うAdviceを適用するなんていう場合.直接ターゲットのメソッドを実行するとトランザクションが開始されません.リトライをするには,MethodInvocationが必要ですが,ThrwosAdviceにはそれがない.なので使えません.

  • 例外を無視できない.

例外を再スローしなくても,元の例外がスローされていきます.例外を握りつぶす手段がありません.例外ハンドリングの主たる目的はその例外を捕まえて例外的な状況から正常な状況に戻すことなのに,それができない.なので使えません.


要するにSpringのThrwosAdviceは単なる傍観者にしかなれないわけです.これじゃあいまいち使えません.
それで嘆いていたSpringerに救世主,ひがさんのThrowsInterceptorは両方の問題を解消してくれる素敵なしろものです.ということで,さっそく実験してみました.ネタは「AOPその8 Throws Advice」そのままです.
まずはIgnoreExceptionAdviceThrowsInterceptorを継承するように修正します.

package study;
import org.aopalliance.intercept.MethodInvocation;

public class IgnoreExceptionAdvice extends ThrowsInterceptor {
    public void handleThrowable(Exception e, MethodInvocation methodInvocation) {
    }
}

ほとんど何も変わっていません.もともと何もしていませんからね.
これ以外の定義ファイルやAdviceを適用するFoo,実行用のMainクラスはそのまま同じものを使って実行!!

こんな仕事やってられるか!
こんな仕事やってられるか!
こんな仕事やってられるか!

素晴らしい!!!
不満をもみ消して,いやな仕事をきっちり三回やらせることができました! これがやりたかったんですよ!
なおThrowsInterceptorは,ひがさんの日記からコピペしたものにimport文を追加した以外,まったく修正していません.何も問題なしです.


いいなぁ,これ.S2とSpringで完全に同じものが使えるといいのですが,AopConfigExceptionはSpringのものですよね? これをS2で使うわけにはいかないですよねぇ.こういう例外もAOP Allianceで一通り決めてくれればいいんですけどね.無念だ.
ということで,ひがさん,バッチリです!