# 基本概念
? ? ?IoC(Inversion of Control),直觀地講,就是對象創建或查找對象依賴的控制權由應用代碼轉到了外部容器,控制權的轉移是所謂反轉。使用Ioc,一個對象依賴的其它對象會通過被動的方式傳遞進來,而不是這個對象自己創建或者查找依賴對象。我們可以認為IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它
? ? ?IoC還有另外一個名字——“依賴注入DI(Dependency Injection)”。從名字上理解,所謂依賴注入,即組件之間的依賴關系由容器在運行期決定,形象地說,即由容器動態地將某種依賴關系注入到組件之中。
# IoC場景
? ? 上面說的可能有點暈,來一個實際點的例子。
? ? 麗薩已經老大不小了,一直沒有男朋友,看著別人恩恩愛愛的,也不禁想找個BoyFriend。擺在她面前的有3種方案:主動“邂逅”?Or 同事介紹 Or 父母包辦。她會選擇哪種呢?

? ? 主動“邂逅”方式,如圖所示:

~~~
public class Girl {
public void kiss(){
Boy boy = new Boy();
}
}
~~~
? ? ?不過這種美好的純潔的愛情,一般只會發生在校園里,對于已經是工薪階層的麗薩顯然不太適合。
? ? 第二方案,同事介紹,

~~~
public class Girl {
void kiss(){
Boy boy = BoyFactory.createBoy();
}
}
~~~
? ? ?很多人都是這樣找到了自己的另一半。麗薩以前也試著去跟同事介紹的handsome man接觸過,但是真人與介紹的出入太大,最起碼handsome這條就不太符合,而且有他許多缺點。覺得他不適合自己,所以最后也就不了了之。
? ? ?所以無奈之下,她的難題丟給了父母。父母給她物色了一個“絕世好男人”——曾小賢(這娃有句經典臺詞:“好男人就是我,我就是....曾小賢”),終于算是遂了她的心愿了。

~~~
public class Girl {
void kiss(Boy boy){
// kiss boy
boy.kiss();
}
}
~~~
? ? ?雖然在現實生活中我們都希望與自己的另一半來場完美的邂逅,但在Spring世界里,跟麗薩一樣,選擇的卻是父母包辦,它就是控制反轉,而這里具有控制力的父母,就是Spring所謂的容器概念。?
? ? ?典型的IoC可以如圖所示。

# ?實例說明IoC注入方式
? ?IoC有3種注入方式:接口注入、Setter方法注入、構造器注入。由于接口注入不推薦使用,所以只介紹setter方法注入和構造器注入。
? ? ?用代碼來說明一切吧:
【Girl.java】
~~~
package com.tgb;
/**
* 期待找BF的Girl
* @author Admin
*
*/
public class Girl {
private Boy bf;
public Girl(){}
public Girl(Boy bf){
System.out.print("使用構造方法方式注入:");
this.bf = bf;
}
public void setBf(Boy bf) {
System.out.print("使用Setter方式注入:");
this.bf = bf;
}
public void kissYourBF() {
bf.kiss();
}
}
~~~
【Boy.java】
~~~
package com.tgb;
/**
* 合格的BF
* @author Admin
*
*/
public class Boy {
public void kiss(){
System.out.println("My boy friend,I'll kiss you!");
}
}
~~~
【Client客戶端】
~~~
package com.tgb;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] agrs){
ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
Girl lisa = (Girl)factory.getBean("girl");
lisa.kissYourBF();
}
}
~~~
【applicationContext.xml配置文件】
~~~
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="boy" class="com.tgb.Boy" />
<bean id="girl" class="com.tgb.Girl">
<!--構造器注入-->
<constructor-arg ref="boy"></constructor-arg>
<!--Setter方法注入-->
<!--<property name="bf" ref="boy"></property>-->
</bean>
</beans>
~~~
? ? ?選擇Setter方法注入和構造器注入的控制是在配置文件中完成的。結果如下:


? ? Setter方法注入時,有2種裝載方式需要注意,byName和byType。當我在配置文件中,把2種注入方式都注釋掉,同時添加了default-autowire="byType",
~~~
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
default-autowire="byType"
>
<bean id="boy" class="com.tgb.Boy" />
<bean id="girl" class="com.tgb.Girl">
<!--構造器注入-->
<!--<constructor-arg ref="boy"></constructor-arg>-->
<!--Setter方法注入-->
<!--<property name="bf" ref="boy"></property>-->
</bean>
</beans>
~~~
? ? ?執行結果如圖:

? ? ?但是換成default-autowire="byName",則會報如下錯誤:

? ? ?這是為什么呢?原因在于,當使用byType方式裝載時,Spring是根據classType來確定要實例化的類。所以就算bean的id是boy,跟Girl中bf的Setter名字不一致,依舊可以實例化。但是使用byName時,則是根據id來實例化類的。所以只要把Boy類對應的bean id跟Girl中的setter方法名一致才行,即修改id="boy"為id="bf",即可正常顯示:
~~~
<bean id="bf" class="com.tgb.Boy" />
<bean id="girl" class="com.tgb.Girl">
<!--構造器注入-->
<!--<constructor-arg ref="boy"></constructor-arg>-->
<!--Setter方法注入-->
<!--<property name="bf" ref="boy"></property>-->
</bean>
~~~
? ? ?另一種修改方式就是用顯示的方式來設定Setter方法所注入的是哪個類的對象:
~~~
<bean id="boy" class="com.tgb.Boy" />
<bean id="girl" class="com.tgb.Girl">
<!--構造器注入-->
<!--<constructor-arg ref="boy"></constructor-arg>-->
<!--Setter方法注入-->
<property name="bf" ref="boy"></property>
</bean>
~~~
? ? ?執行結果如圖:

### **2種注入方式的比較**
? ? ?Setter 注入:
- 對于習慣了傳統 javabean 開發的程序員,通過 setter 方法設定依賴關系更加直觀。
- 如果依賴關系較為復雜,那么構造子注入模式的構造函數也會相當龐大,而此時設值注入模式則更為簡潔。
- 如果用到了第三方類庫,可能要求我們的組件提供一個默認的構造函數,此時構造子注入模式也不適用。
? ? ?構造器注入:
- 在構造期間完成一個完整的、合法的對象。
- 所有依賴關系在構造函數中集中呈現。
- 依賴關系在構造時由容器一次性設定,組件被創建之后一直處于相對“不變”的穩定狀態。
- 只有組件的創建者關心其內部依賴關系,對調用者而言,該依賴關系處于“黑盒”之中。
- 前言
- Struts 簡單小結
- 深入淺出了解Struts的處理流程(有圖有真相)
- struts標簽+jstl標簽之國際化實例
- 一口一口吃掉Hibernate(二)——別被世俗蒙蔽了雙眼:Hibernate中Session之get和load方法的真正區別
- 一口一口吃掉Hibernate(一)——使用SchemaExport生成數據表
- 一口一口吃掉Hibernate(三)——Hibernate給表和字段設置前后綴及分隔符
- 一口一口吃掉Hibernate(四)——多對一單向關聯映射
- 一口一口吃掉Hibernate(五)——一對多單向關聯映射
- 一口一口吃掉Hibernate(六)——多對多關聯映射
- 一口一口吃掉Hibernate(七)——繼承映射
- 一口一口吃掉Hibernate(八)——Hibernate中inverse的用法
- 一覽Spring全貌
- 包辦婚姻的Spring IoC
- 3幅圖讓你了解Spring AOP
- Spring Aop實例之xml配置
- Spring Aop實例之AspectJ注解配置