在 第一個 Spring 程式
中利用Bean的Setter完成依賴注入,Spring鼓勵的是Setter injection,也就是Type 2,但也允許您使用Type
3的Constructor
injection,使用Setter或Constructor來注入依賴關係視您的需求而定,這邊先來看看如何使用Constructor
injection,首先看看HelloBean:
package onlyfun.caterpillar;
public class HelloBean { private String name; private String helloWord;
public HelloBean() { } public HelloBean(String name, String helloWord) { this.name = name; this.helloWord = helloWord; } public void setName(String name) { this.name = name; } public String getName() { return name; }
public void setHelloWord(String helloWord) { this.helloWord = helloWord; } public String getHelloWord() { return helloWord; } }
注意建構函式的兩個參數順序,在Bean定義檔中設定時必須指定參數的順序,如下所示:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="helloBean" class="onlyfun.caterpillar.HelloBean"> <constructor-arg index="0"> <value>Justin</value> </constructor-arg> <constructor-arg index="1"> <value>caterpillar</value> </constructor-arg> </bean> </beans>
在Bean的定義檔案中,使用<constructor-arg>來表示將使用Constructor
injection,由於使用Constructor injection時並不如Setter
injection時擁有setXXX()這樣易懂的名稱,所以必須指定參數的位置索引,index屬性就是用於指定物件將注入至建構函式中的哪一個參
數,參數的順序指定中,第一個參數的索引值是0,第二個是1,依此類推。
來看看測試程式:
package onlyfun.caterpillar;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext("beans-config.xml"); HelloBean hello = (HelloBean) context.getBean("helloBean"); System.out.print("name: "); System.out.println(hello.getName()); System.out.print("word: "); System.out.println(hello.getHelloWord()); } }
實際的執行結果如下:
資
訊: Unable to locate ApplicationEventMulticaster with name
'applicationEventMulticaster': using default
[org.springframework.context.event.SimpleApplicationEventMulticaster@12b6651]
2005/10/17 下午 09:08:50 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
資訊: Pre-instantiating
singletons in factory
[org.springframework.beans.factory.support.DefaultListableBeanFactory
defining beans [helloBean]; root of BeanFactory hierarchy]
name: Justin
word: caterpillar |
這邊的例子在Bean上使用具有兩個參數的建構函式作範例,如果建構函式上只有一個參數,則不必指定index屬性,例如建構函式上若只有一個name參數,則可以在Bean定義檔中如下設定:
...
<bean ...>
<constructor-arg>
<value>Justin</value>
</constructor-arg>
</bean>
...
另一個例子是若有兩個以上的參數,而參數型態各不相同的話,例如若HelloBean是這麼定義的:
package onlyfun.caterpillar;
public class HelloBean { private String name; private Integer age;
public HelloBean() { } public HelloBean(String name, Integer age) { this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return name; }
public void setAge(Integer age) { this.age = age; } public Integer getAge() { return age; } }
這次在Bean定義檔的<constructor-arg>上,可以使用type來指定建構函式上的參數型態,例如:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="helloBean" class="onlyfun.caterpillar.HelloBean"> <constructor-arg type="java.lang.String"> <value>Justin</value> </constructor-arg> <constructor-arg type="java.lang.Integer"> <value>20</value> </constructor-arg> </bean> </beans>
簡單的將SpringDemo類別改為以下:
package onlyfun.caterpillar;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringDemo { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext("beans-config.xml"); HelloBean hello = (HelloBean) context.getBean("helloBean"); System.out.print("name: "); System.out.println(hello.getName()); System.out.print("word: "); System.out.println(hello.getAge()); } }
執行結果如下所示:
...
name: Justin
word: 20
... |
至於要使用Constructor或Setter來完成依賴注入這個問題,其實就等於在討論一個古老的問題,要在物件建立時就準備好所有的資源,或是在物件建立好後,使用Setter來進行設定。
使用Constructor的好處之一是,您可以在建構物件的同時一併完成依賴關係的建立,物件一建立則所有的一切也就準備好了,但如果要建立的物件關係很多,使用Constructor
injection會在建構函式上留下一長串的參數,且不易記憶,這時使用Setter會是個不錯的選擇,另一方面,Setter可以有明確的名稱可以瞭解注入的物件
會是什麼,像是setXXX()這樣的名稱會比記憶Constructor上某個參數位置代表某個物件來得好。
然而使用Setter由於提供了setXXX()方法,所以不能保證相關的資料成員或資源在執行時期不會被更改設定,所以如果您想要讓一些資料成員或資源變為唯讀或是私有,使用Constructor injection會是個簡單的選擇。
|