Spring Framework 入門記 Beanその1 id/name属性とsingleton属性
いつまで続くか,Spring Frameworkの入門記録です.
「はじめてのSpring Framework」で作成した定義ファイルでは,bean
要素にname
属性を指定していました.
<bean name="foo" class="study.Foo">
bean
要素には,name
属性の他にid
属性というのもあります.「Spring Framework Reference Documentation」の「3.2.4 The bean identifiers(id
and name
)」によると,id
はBeanFactory
(コンテナ)中の全てのbeanを一意に識別するものだそうです.
それではname
属性はどういうもの? というと,3.2.4節には何も書かれていないのですが,「Appendix A. Spring's beans.dtd」に説明がありました.それによると,name
属性はid
属性の別名(alias)ということで,スペースまたはカンマで区切って複数指定できるということです.
それでは,ということで...
<bean id="akiko" name="seri wakaba" class="study.Foo">
とすると,"akiko"
,"seri"
,"wakaba"
いずれの名前でもインスタンスを取得することが出来ました.
なお,id
属性はDTDでID型として定義されているので,定義ファイル中で重複した値を記述することは出来ません(バッチリ例外が吹っ飛んできました).
一方,name
属性はCDATA型なので,XMLの検証レベルでは値の重複が許されます.実際に値が重複するとどうなるのかなぁ,と思い,
<bean id="yada" name="akiko" class="study.Foo"> <bean id="wada" name="akiko" class="study.Foo">
としてみたところ,
org.springframework.beans.factory.BeanDefinitionStoreException: Cannot register alias 'akiko' for bean name 'wada': it's already registered for bean name 'yada'
ということで,name
属性の個々の値についても,定義ファイル中で一意にしなければならないようです.
では,id
属性の値とname
属性の値が重複した場合はどうなるのかなぁ,と思い,
<bean id="yuri" name="ebihara" class="study.Foo"> <bean id="ebihara" name="yuri" class="study.Foo">
としてみたところ,これは問題なく通りました.ですが,自分の先入観とは異なり,name
属性の方でインスタンスが引っかかりました.上の例だと,"yuri"
を指定するとBeanFactory
は下の定義のインスタンス(name
が"yuri"
の方)を返します.どうやら,BeanFactory#getBean(String)
に渡した文字列(ここでは"yuri"
)は,それに対する別名が定義されていればその値(ここでは"ebihara"
)に変換され,それをキーとしてbeanのインスタンスを探すようです.
さて,BeanFactory
クラスには,保持しているbeanの名前の配列を返すgetBeanDefinitionNames()
というメソッドがあります.ここでいうdefinitionNamesとはどういう名前(id
or name
)なのかな,ということで,
<bean id="akiko" class="study.Foo"> <bean name="yuri" class="study.Foo"> <bean id="nakama" name="yukie" class="study.Foo">
としてみたところ,"akiko"
,"nakama"
,"yuri"
が取得できました.id
属性があればその値が,なければname
属性の値が採用されているようです.
ふと,id
属性もname
属性もない場合はどうなるのかなぁ,なんて思ったのでやってみると,beanのクラス名(完全限定名)が採用されていました.ちなみに,同一クラスの名無しのbeanを複数記述してもエラーにはならないのですが,有効な(完全限定名で取得できる)インスタンスは定義ファイル中で最後に記述したものだけになりました.上書きされるんですね.
name
属性は,名前空間をクラス階層に限定するなどの付加価値もないようですし,あまり必要性を感じることができませんでした.基本的にid
属性を使っていくことにします.
なんだか,全然本質的でないところでのんびりしてしまいました.とりあえず次へ行くことにします.
次は「3.2.5. To sinleton or not to singleton」です.
bean
要素には,singleton
という属性があります.この属性は列挙型で,true
またはfalse
を指定することが出来ます.デフォルトはtrue
です.
singleton
属性がtrue
だと,そのbeanのインスタンスはBeanFactory
中に一つだけ生成され,共有されます.つまり,何度BeanFactory#getBean(String)
を呼び出しても,同じインスタンスが返ってきます.
一方,singleton
属性がfalse
だと,BeanFactory#getBean(String)
が呼び出されるたびに新しいインスタンスが返ってきます.こちらはsingletonに対してprototypeと呼ばれるようですが,Prototypeパターンが使われているということでしょうか?
なお,singletonでもprototypeでも,取得したインスタンスをBeanFactory
に戻す必要はないようです.AvalonではComponentManager
から取得したインスタンスはライフサイクルに関わらず戻すのが作法だった(と思う)ので,少し落ち着かない感じがあります.Avalonの場合,Component
(後にService
と改称されてしまいました)をComponentManager
へ戻したタイミングで,ComponentManager
がComponent
の後処理(もしあれば)を呼び出してくれました.しかしSpring Frameworkでは,少なくともprototypeなbeanの後処理は,beanの利用者が責任を負わなくてはならないのですね.まぁ,コネクションプールなんかもそういうものですから(DataSource
から取得したConnection
は利用者がclose()
する),Avalonがイレギュラーだったのかもしれません.
なんだか遅々として進んでいない感じですが,どうせ出遅れているのでじっくりと...
次回はIoC/Dependency Injectionの名前の由来らしいネタ,「3.3. Properties, collaborators, autowiring and dependency checking」に取り組みたいと思います.