入門 05 - Constructor注入 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Spring鼓勵的是setter injection,但也允許您使用constructor injection,使用setter或constructor來注入依賴關係視您的需求而定,這邊先來看看如何使用construtor injection,首先看看HelloBean:
HelloBean.java
package onlyfun.caterpillar;
public class HelloBean {
private String helloWord = "hello";
private String user = "NoBody";
public HelloBean(String helloWord, String user) {
this.helloWord = helloWord;
this.user = user;
}
public String sayHelloToUser() {
return helloWord + "!" + user + "!";
}
}
爲了突顯建構函式,我們這個HelloBean設計的簡陋,只提供了建構函式與必要的sayHelloToUser(),我們來看看bean的定義檔案:
bean.xml
<?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>Greeting</value></constructor-arg>
<constructor-arg index="1"><value>Justin</value></constructor-arg>
</bean>
</beans>
在bean的定義檔案中,我們使用<constructor-arg>來表示我們將使用 constructor injection,由於使用constructor injection時並不如setter injection時擁有setXXX()這樣易懂的名稱,所以我們必須指定參數的位置索引,index屬性就是用於指定我們的對象將注入至建構函式中的哪一個參數,索引值從0開始,符合Java索引的慣例。
來看看測試程序:
Test.java
package onlyfun.caterpillar;
import java.io.*;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("bean.xml");
BeanFactory factory = new XmlBeanFactory(is);
HelloBean hello = (HelloBean) factory.getBean("helloBean");
System.out.println(hello.sayHelloToUser());
}
}
實際的執行結果如下:
2004/10/21 下午 03:53:58 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from resource for InputStream
2004/10/21 下午 03:54:02 org.springframework.beans.factory.support.AbstractBeanFactory getBean
信息: Creating shared instance of singleton bean 'helloBean'
2004/10/21 下午 03:54:03 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory autowireConstructor
信息: Bean 'helloBean' instantiated via constructor [public onlyfun.caterpillar.HelloBean(java.lang.String,java.lang.String)]
Greeting!Justin!
要討論使用constructor或setter來完成依賴注入這個問題,其實就等於在討論一個古老的問題,要在對象建立時就準備好所有的資源,或是在對象建立好後,使用setter來進行設定。
使用constructor的好處之一是,您可以在建構對象的同時一併完成依賴關係的建立,如果要建立的對象關係很多,使用 constructorinjection會在建構函式上留下一長串的參數,這時使用setter會是個不錯的選擇,另一方面, setter可以有明確的名稱可以瞭解注入的對象會是什麼,像是setXXX()這樣的名稱會比記憶constructor上某個參數位置代表某個對象來得好。
然而使用setter由於提供了setXXX()方法,所以不能保證相關的field成員或資源在執行時期不會被更改設定,所以如果您想要讓一些field成員或資源變爲只讀或是私有,使用constructor injection會是個簡單的選擇。