一、說到依賴注入(控制反轉),先要理解什麼是依賴。
Spring 把相互協作的關係稱爲依賴關係。假如 A 組件調用了 B 組件的方法,我們可稱A 組件依賴於 B 組件。
二、什麼是依賴注入。
在傳統的程序設計過程中,通常由調用者來創建被調用者的實例。
在依賴注入的模式下,創建被調用者的工作不再由調用者來完成,因此稱爲控制反轉;創建被調用者實例的工作通常由Spring 容器來完成,然後注入給調用者,因此也稱爲依賴注入。
三、依賴注入的好處。
依賴注入讓 Spring 的 Bean 以被指文件組織在一起,而不是以硬編碼的方式耦合在一起。程序完成無須理會被調用者的實現,也不無須主動定位工廠,這是最好的解耦方式。實例之間的依賴關係由
IoC 容器負責管理。
四、依賴注入的 Spring 實現
1、設值注入
設值注入是指 IoC 容器使用屬性的 setting 方法來注入被依賴的實例。
先創建一個實體對象(Bean)
[java] view plaincopy
public class HelloWorld {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
再配置文件applicationContext.xml,實例化bean
[java] view plaincopy
<bean id="helloBean" class="com.spring.demo.HelloWorld">
<property name="msg" value="Hello World!"/>
</bean>
最後測試是否能夠得到注入的bean,並打印出對象的屬性。
[java] view plaincopy
public static void main(String[] args){
//讀取配置文件,獲得BeanFactory
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanFactory factory = context;
HelloWorld hello = (HelloWorld)factory.getBean("hello");
System.out.println(hello.getMsg());
}
2、構造注入
除了設值注入,還有另一種注入方式,這種方式在構造實例時,已爲其完成了依賴關係的初始化。這種利用構造器來設置依賴關係的方式,被稱爲構造注入。
先創建一個實體對象(Bean)
[java] view plaincopy
public class HelloWorld {
private String msg;
//需要一個默認無參構造器
public HelloWorld(){}
public HelloWorld(String msg){
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
再配置文件applicationContext.xml,實例化bean。
[java] view plaincopy
<bean id="hello" class="com.spring.demo.HelloWorld">
<constructor-arg index="0">
<value>HelloWorld!</value>
</constructor-arg>
</bean>
最後測試是否能夠得到注入的bean,並打印出對象的屬性。
[java] view plaincopy
public static void main(String[] args){
//讀取配置文件,獲得BeanFactory
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanFactory factory = context;
HelloWorld hello = (HelloWorld)factory.getBean("hello");
System.out.println(hello.getMsg());
}
五、處理bean依賴關係的步驟
1、根據定義bean的配置創建並初始化BeanFactory實例
2、每個bean的依賴將以屬性、構造器參數、或靜態工廠方法參數的形式出現。當這些bean被實際創建時,這些依賴也將會提供給該bean。
3、每個屬性或構造器參數既可以是一個實際的值,也可以是對該容器中另一個bean的引用。
4、每個指定的屬性或構造器參數值必須能夠被轉換成特定的格式或構造參數所需的類型。
Spring
會在容器被創建時驗證容器中每個bean的配置,包括驗證那些bean所引用的屬性是否指向一個有效的bean。在bean被實際創建之前,bean的屬
性並不會被設置。伴隨着bean被實際創建,作爲該bean的依賴bean以及依賴bean的依賴bean也將被創建和分配。
六、兩種注入方式的對比
1、相比之下,設值注入具有如下的優點:
(1)、與傳統的 JavaBean 的寫法更相似,程序開發人員更容易理解、接受。通過 Setting 方法設定依賴關係顯得更加直觀、自然。
(2)、對於複雜的依賴關係,如果採用構造注入,會導致構造過於臃腫,難以閱讀。Spring 在創建 Bean 實例時,需要同時實例化其依賴的全部實例,因而導致性能下降。而使用設值注入,則能避免這些問題。
(3)、尤其是在某些屬性可選的情況下,多參數的構造器更加笨重。
2、構造注入也不是絕對不如設值注入,在某些特定的場景下,構造注入比設值注入更優秀。構造注入也有如下優勢:
(1)、構造注入可以在構造器中決定依賴關係的注入順序,有限依賴的優先注入。例如,組件中某些其他依賴關係的注入,嚐嚐需要依賴於 Datasource 的注入。採用構造注入,可以在代碼中清晰地決定注入順序。
(2)、對於依賴關係無須變化的 Bean ,構造注入更有用處。因爲沒有 setting 方法,所有的依賴關係全部在構造器內設定。因此,無須擔心後續代碼對依賴關係產生的破壞。
(3)、依賴關係只能在構造器中設定,則只有組件的創建者才能改變組件的依賴關係。對組件的調用者而言,組件內部的依賴關係完成透明,更符合高內聚的原則。
兩種方式總結:建議採用以設值注入爲住,構造注入爲輔的注入策略。對於依賴關係無須變換的注入,儘量採用構造注入;而其他的依賴關係的注入,則考慮採用設值注入。