IoC(Inversion of Control),直觀地講,就是對象建立或查找對象依賴的控制權由應用代碼轉到了外部容器,控制權的轉移是所謂反轉。使用Ioc,一個對象依賴的其它對象會經過被動的方式傳遞進來,而不是這個對象本身建立或者查找依賴對象。咱們能夠認爲IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它html
IoC還有另一個名字——「依賴注入DI(Dependency Injection)」。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象地說,即由容器動態地將某種依賴關係注入到組件之中。java
上面說的可能有點暈,來一個實際點的例子。程序員
麗薩已經老大不小了,一直沒有男友,看着別人恩恩愛愛的,也不由想找個BoyFriend。擺在她面前的有3種方案:主動「邂逅」 Or 同事介紹 Or 父母包辦。她會選擇哪一種呢?spring
主動「邂逅」方式,如圖所示:app
public class Girl { public void kiss(){ Boy boy = new Boy(); } }不過這種美好的純潔的愛情,通常只會發生在校園裏,對於已是工薪階層的麗薩顯然不太適合。
第二方案,同事介紹,函數
public class Girl { void kiss(){ Boy boy = BoyFactory.createBoy(); } }
不少人都是這樣找到了本身的另外一半。麗薩之前也試着去跟同事介紹的handsome man接觸過,可是真人與介紹的出入太大,最起碼handsome這條就不太符合,並且有他許多缺點。以爲他不適合本身,因此最後也就不了了之。this
因此無奈之下,她的難題丟給了父母。父母給她物色了一個「絕世好男人」——曾小賢(這娃有句經典臺詞:「好男人就是我,我就是....曾小賢」),終於算是遂了她的心願了。spa
public class Girl { void kiss(Boy boy){ // kiss boy boy.kiss(); } }
雖然在現實生活中咱們都但願與本身的另外一半來場完美的邂逅,但在Spring世界裏,跟麗薩同樣,選擇的倒是父母包辦,它就是控制反轉,而這裏具備控制力的父母,就是Spring所謂的容器概念。 code
典型的IoC能夠如圖所示。
xml
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方法注入時,有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>執行結果如圖:
Setter 注入:
構造器注入: