コンストラクタを介したDependency Injection(Spring1.2RC2)
前頁ではsetterを使用したDependency Injectionの設定と実装を行った.既存プログラムにSpringを導入する場合等には,コンストラクタを使用するDependency Injectionの設定と実装を行いたい場合も想定されうる.そしてSpringはそれをサポートしているようなので,試してみた.
今までのサンプルでは要素beanの子要素propertyを設定することで,beanのsetter呼び出しを介した値の設定を行ってきた.
本頁のサンプルでは,要素beanの子要素constructor-argを設定することで,beanのコンストラクタを介した値の設定を行う.
サンプルのbeans.xmlを以下に示す.
属性idの値がtopBeanType1-1である要素beanが最も簡単なパターンである.
ポイントは以下.
- 他のbeanをコンストラクタに渡す
- 要素propertyと同様,要素refを子要素に記述する.
<constructor-arg><ref bean="innerBeanType1"/></constructor-arg>
- プリミティブ型をコンストラクタに渡す
- 要素constructor-argの属性typeに型を記述する.
さらに子要素valueで値を指定する.
<constructor-arg type="double"><value>1.5</value></constructor-arg>
要素propertyの場合は,属性nameの値xxxから,"setXxx"という名前のメソッド(引数は一つ)を探すことで,Springはその仕事を果たすことができた.
要素constructor-argの場合は,Springにはオーバーロードを考慮した設定をしなければならない.
以下はTopBeanType1のソースである.
TopBeanType1にはコンストラクタが二つある.
一方は前節に挙げた属性idの値がtopBeanType1-1である要素beanで使用した.
public TopBeanType1 (InnerBean paramInnerBean, double paramTopValue) {
もう一つは属性idの値がtopBeanType1-2である要素beanで使用する.
public TopBeanType1 (InnerBean paramInnerBean,
InnerBean paramInnerBean2,
int paramIntTopValue,
double paramTopValue) {
同じ型の引数が二つある(paramInnerBeanとparamInnerBean2).
これらを識別するために,Springは記述した順番ではなく,要素constructor-argの属性indexを使用する.
<constructor-arg index="0"><ref bean="innerBeanType1"/></constructor-arg> <constructor-arg index="1"><ref bean="innerBeanType2"/></constructor-arg>属性indexは何番目の引数かを意味し,0からはじまる. なお,3番目と4番目の引数(paramIntTopValueとparamTopValue)は,コンストラクタを一意に特定でき,その一意なコンストラクタ内で引数が型によって一意に決まるので,属性indexはなくても動作する. もし,TopBeanType1に以下のコンストラクタがあれば(intの引数とdoubleの引数の順番が逆),indexを指定しないとコンストラクタを一意に特定できない.
public TopBeanType1 (InnerBean paramInnerBean,
InnerBean paramInnerBean2,
double paramTopValue,
int paramIntTopValue) {
サンプル中のコメントアウトされた上記メソッドを有効にし,同じbeans.xmlで実行すると,ソース上先に記述されているコンストラクタが呼び出された.
若干バグっぽいが(エラーとすべき?),こういったトラブルを避ける意味でも,属性indexは指定する方が「行儀がよい」ということになるだろうか.
以下はTopBeanType2のソースである.
属性idの値がtopBeanType2である要素beanでは,TopBeanType2を以下のコンストラクタでインスタンス化する.
public TopBeanType2 (InnerBean paramInnerBean,
InnerBean paramInnerBean2,
double paramTopValue,
double paramTopValue2) {
同じ型の引数が二組ある(paramInnerBeanとparamInnerBean2,paramTopValueとparamTopValue2).
したがって四つの要素constructor-argにはすべて属性indexを指定する必要がある.
<constructor-arg index="0"><ref bean="innerBeanType1"/></constructor-arg> <constructor-arg index="1"><null/></constructor-arg> <constructor-arg index="2" type="double"><value>1.5</value></constructor-arg> <constructor-arg index="3" type="double"><value>2.5</value></constructor-arg>さて,二番目の要素constructor-argの子要素には空要素nullを指定している. これによってコンストラクタの該当引数にはnullが指定される.
サンプルのドライバクラスHelloBeanFactoryは前頁のサンプルと同じである.
実行すると以下のログがでた.
2005-05-08 16:12:54,909 INFO [main] xml.XmlBeanDefinitionReader:132 - Loading XML bean definitions from URL [jar:file:/home/matsu/programing/java/spring/dicontainer7/springsample.jar !/org/fireproject/springsample/beans.xml] 2005-05-08 16:12:55,009 INFO [main] support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'topBeanType1-1' 2005-05-08 16:12:55,103 INFO [main] support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'innerBeanType1' 2005-05-08 16:12:55,157 INFO [main] springsample.HelloBeanFactory:32 - ====org.fireproject.springsample.TopBeanType1 [topValue=1.5;intTopValue=0; innerBean=org.fireproject.springsample.InnerBeanType1[innerValue=10;];innerBean2=null] 2005-05-08 16:12:55,158 INFO [main] support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'topBeanType1-2' 2005-05-08 16:12:55,159 INFO [main] support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'innerBeanType2' 2005-05-08 16:12:55,172 INFO [main] springsample.HelloBeanFactory:32 - ====org.fireproject.springsample.TopBeanType1 [topValue=2.5;intTopValue=1;innerBean=org.fireproject.springsample.InnerBeanType1[innerValue=10;]; innerBean2=org.fireproject.springsample.InnerBeanType2[innerValue=-20;]] 2005-05-08 16:12:55,172 INFO [main] support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'topBeanType2' 2005-05-08 16:12:55,185 INFO [main] springsample.HelloBeanFactory:32 - ====org.fireproject.springsample.TopBeanType2[topValue=1.5;topValue2=2.5; innerBean=org.fireproject.springsample.InnerBeanType1[innerValue=10;];innerBean2=null]

