包辦婚姻的Spring IoC

基本概念

       IoC(Inversion of Control),直觀地講,就是對象建立或查找對象依賴的控制權由應用代碼轉到了外部容器,控制權的轉移是所謂反轉。使用Ioc,一個對象依賴的其它對象會經過被動的方式傳遞進來,而不是這個對象本身建立或者查找依賴對象。咱們能夠認爲IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它html


       IoC還有另一個名字——「依賴注入DI(Dependency Injection)」。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象地說,即由容器動態地將某種依賴關係注入到組件之中。java


IoC場景

      上面說的可能有點暈,來一個實際點的例子。程序員


      麗薩已經老大不小了,一直沒有男友,看着別人恩恩愛愛的,也不由想找個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注入方式

      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 方法設定依賴關係更加直觀。
    • 若是依賴關係較爲複雜,那麼構造子注入模式的構造函數也會至關龐大,而此時設值注入模式則更爲簡潔。
    • 若是用到了第三方類庫,可能要求咱們的組件提供一個默認的構造函數,此時構造子注入模式也不適用。

       構造器注入:

    • 在構造期間完成一個完整的、合法的對象。
    • 全部依賴關係在構造函數中集中呈現。
    • 依賴關係在構造時由容器一次性設定,組件被建立以後一直處於相對「不變」的穩定狀態。
    • 只有組件的建立者關心其內部依賴關係,對調用者而言,該依賴關係處於「黑盒」之中。
相關文章
相關標籤/搜索