ファイヤープロジェクト
autowrite(Spring1.2)
2005-05-31T11:30+09:00   matsu
要素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となる.
後述のサンプルで試してみたところ,byTypeやconstructorは動きがよくわからない. 要素beanの子要素に要素propertyや要素constructor-argがある場合は,autowrite設定はこれらの要素で上書きされる.
以下に本頁のサンプルの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[]]
matsu(C)
Since 2002
Mail to matsu