autowrite(Spring1.2)
要素beanの属性autowriteを指定することによって,設定することなく自動的に依存beanをsetしれくれるようなので,試してみた.
要素beanには属性autowriteがある.
これによって,要素propertyやその子要素のref等を記述することなく,依存beanを該当beanに自動的に設定しれくれる.
属性autowriteの値は,依存beanを特定する方法によっていくつかある.
- no
- autowriteしない. 属性autowriteのデフォルトである.
- byName
- beanのsetterメソッド名と,beanのnameやidによって依存beanを特定する. 例えばsetHoge(...)というメソッドがあれば,nameかidがhogeというbeanを探し,それをsetする. マッチするものが無ければ,何もsetされない.
- byType
- beanのsetterメソッドの引数の型と,beanのクラスによって依存beanを特定する. 例えばsetXxx(Hoge ...)というメソッドがあれば,Hogeというクラスを使用するbean設定を探し,それをsetする. マッチするものが無ければ,なにもsetされない. もし同じクラスで複数のbean設定があれば,fatal errorが投げられる. そのようなbeanに対しては,byTypeは使用すべきではない.
- constructor
- byTypeと似ているが,beanのsetterではなくコンストラクタの引数の型とbeanのクラスによって依存beanを特定する. 異なるbeanを引数にもつオーバーロードがあると,fatal errorが投げられる.
- autodetect
- constructorとbyTypeのどちらかを自動判定する. デフォルトコンストラクタがある場合は,byTypeとなる.
以下に本頁のサンプルのbeans.xmlを示す.
どのbean設定に該当するのか特定するため,各bean設定に
以上を踏まえて,実行結果を以下に示す.
<property name="msg"><value>byNameMsg</value></property>を突っ込んである. この設定はbeanをtoStringした際に出力される. beanのクラスであるTopBeanType1.javaを以下に示す.
2005-05-31 10:52:09,123 INFO [main] xml.XmlBeanDefinitionReader:132 - Loading XML bean definitions from URL [ jar:file:/home/matsu/programing/java/spring/dicontainer12/springsample.jar !/org/fireproject/springsample/beans.xml] 2005-05-31 10:52:09,225 INFO [main] support.AbstractBeanFactory:218 - Creating shared instance of singleton bean 'topBeanType1ByType' 2005-05-31 10:52:09,229 INFO [main] springsample.TopBeanType1:37 - constructor () 2005-05-31 10:52:09,347 INFO [main] core.CollectionFactory:61 - JDK 1.4+ collections available 2005-05-31 10:52:09,371 INFO [main] core.CollectionFactory:66 - Commons Collections 3.x available 2005-05-31 10:52:09,377 INFO [main] support.AbstractBeanFactory:218 - Creating shared instance of singleton bean 'innerBean' 2005-05-31 10:52:09,380 INFO [main] springsample.InnerBeanType1:11 - org.fireproject.springsample.InnerBeanType1 is created. 2005-05-31 10:52:09,412 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byTypeMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]] 2005-05-31 10:52:09,412 INFO [main] support.AbstractBeanFactory:218 - Creating shared instance of singleton bean 'topBeanType1ByName' 2005-05-31 10:52:09,413 INFO [main] springsample.TopBeanType1:37 - constructor () 2005-05-31 10:52:09,414 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byNameMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]] 2005-05-31 10:52:09,415 INFO [main] support.AbstractBeanFactory:218 - Creating shared instance of singleton bean 'topBeanType1ByConstructor' 2005-05-31 10:52:09,420 INFO [main] springsample.TopBeanType1:13 - constructor (InnerBean param) 2005-05-31 10:52:09,421 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byConstructorMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]] 2005-05-31 10:52:09,422 INFO [main] support.AbstractBeanFactory:218 - Creating shared instance of singleton bean 'topBeanType1ByAutoDetect' 2005-05-31 10:52:09,422 INFO [main] springsample.TopBeanType1:37 - constructor () 2005-05-31 10:52:09,426 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byAutodetectMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]]autowriteによってうまく依存beanも取得できている. サンプルをいくつか修正して実行すると,前節の仕様の確認ができる.
- byName
- autowrite値がbyNameだと,TopBeanのsetInnerBeanからid値innerBeanのbeanを探す.
したがって,beans.xmlのid値innerBeanを別の値にすると,innberBeanが見付からず,nullとなる.
2005-05-31 10:57:45,537 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byNameMsg;innerBean=null]
- byType
- autwrite値がbyTypeだと,TopBeanのsetInnerBeanの引数がInnerBeanであるから,属性class値がInnerBeanであるbeanを探す.
したがって,beans.xmlのbean設定
<bean id="innerBeanType1-2" class="org.fireproject.springsample.InnerBeanType1"> </bean>を有効にすると,クラスInnerBeanのbeanが二つになり,一意に特定できなくなるので,fatal errorが発生する....省略...UnsatisfiedDependencyException: Error creating bean with name 'topBeanType1ByType' ...省略...Unsatisfied dependency expressed through bean property 'innerBean': There are 2 beans of type [interface org.fireproject.springsample.InnerBean] for autowire by type. There should have been 1 to be able to autowire property 'innerBean' of bean 'topBeanType1ByType'.
- constructor
- TopBeanType1にはコメントアウトされたコンストラクタがある.
これを全て有効にすると,以下のようになった.
2005-05-31 11:18:39,306 INFO [main] springsample.TopBeanType1:18 - constructor (InnerBean param, InnerBean param2) 2005-05-31 11:18:39,307 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byConstructorMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]]
引数がInnerBean二つのコンストラクタが呼ばれている... このあたり,詳細な動きがよくわからないが,設定あるいはオーバーロードなどに問題がある場合は,デフォルトコンストラクタがあればそちらが使用されるようだ. - autodetect
- 先の実行例では,TopBeanType1にデフォルトコンストラクタがあったので,コンストラクタにはこれを使用し,autodetectとしては,byTypeと同じ動きとなっていた.
2005-05-31 10:52:09,422 INFO [main] springsample.TopBeanType1:37 - constructor () 2005-05-31 10:52:09,426 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byAutodetectMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]]
TopBeanType1のデフォルトコンストラクタをコメントアウトすると,constructor指定時と同じ動きとなる.// public TopBeanType1() { // super(); // logger.info("constructor ()"); // }これをすると,以下のように他のbean設定をコメントアウトする必要がある.<!--bean id="topBeanType1ByType" class="org.fireproject.springsample.TopBeanType1" autowire="byType"> <property name="msg"><value>byTypeMsg</value></property> </bean> <bean id="topBeanType1ByName" class="org.fireproject.springsample.TopBeanType1" autowire="byName"> <property name="msg"><value>byNameMsg</value></property> </bean-->さらにHelloBeanFactoryも修正する.String[] beanKeys = new String[]{ // "topBeanType1ByType", // "topBeanType1ByName", "topBeanType1ByConstructor", "topBeanType1ByAutoDetect", };これで実行すると,先のautodetectの動きを確認できる.2005-05-31 11:13:01,673 INFO [main] springsample.TopBeanType1:13 - constructor (InnerBean param) 2005-05-31 11:13:01,674 INFO [main] springsample.HelloBeanFactory:33 - ====org.fireproject.springsample.TopBeanType1[ msg=byAutodetectMsg;innerBean=org.fireproject.springsample.InnerBeanType1[]]

