天天看點

Spring 學習筆記 ----依賴注入

依賴注入 有三種方式,本文隻學習下屬性注入.

屬性注入

      屬性注入即通過 setXxx方法()注入Bean的屬性值或依賴對象,由于屬性注入方式具有可選擇性和靈活性高的優點,是以屬性注入方式是實際應用中最常用的注入方式。

屬性注入的執行個體

屬性注入要求Bean提供一個預設的構造函數,并為需要注入的屬性提供對應的Setter方法。Spring先調用Bean的預設構造函數執行個體化Bean對象,然後通過反射的方式調用Setter方法注入屬性值。先看一個簡單的例子

package com.spring.model;


public class Car {
	/**
	 *  系統為自動我們提供一個無參的構造方法
	 */
	private String brand;
	private String color;
	private int maxSpeed;
	public void setBrand(String brand) {
		this.brand = brand;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}
}
           

Car 類中定義了3個屬性,并提供了對應的Setter方法. 小提示:預設構造函數是不帶參數的構造函數。Java語言規定,如果類中沒有定義任何構造函數,則JVM自動為其生成一個預設的構造函數。反之,如果類中顯示定義了構造函數,則JVM不會為其生成預設的構造函數。是以假設Car類中定義了一個帶參的構造函數,如public Car(String brand),則需要同時提供一個預設構造函數public Car(),否則使用屬性注入時将抛出異常。 下面是在Spring配置檔案中,對Car進行屬性注入時的配置片段.

<bean  id="car" class="com.spring.model.Car" >
        <property name="maxSpeed"><value>200</value></property>
        <property name="brand"><value>紅旗CAT2</value> </property>
        <property name="color"><value>紅色</value></property>
   </bean>
           

我們配置了一個Car Bean,并為該Bean的三個屬性提供了屬性值。具體來說,Bean的每一個屬性對應一個<property>标簽,name為屬性的名稱,在Bean實作類中擁有與其對應的Setter方法:maxSpeed對應setMaxSpeed。

注入參數詳解

字面值

上面使用的方式就是字面值。

引用其它Bean

Spring IOC容器中定義的bean可以互相引用,IOC容器則充當紅娘的角色。下面我們建立一個新的Boss類,Boss類中擁有一個Car類型的屬性:

package com.spring.model;

public class Boss {
   private Car car=new Car();

public Car getCar() {
	return car;
}
           
//設定Car屬性
public void setCar(Car car) {
	this.car = car;
}
           
..........
}
           

boss 的Bean通過<ref>元素引用car Bean,建立起Boss對car的依賴。

<!-- 1 car bean -->      
   <bean  id="car" class="com.spring.model.Car" />
   <bean id="boss" class="com.spring.model.Boss">
        <property name="car">
           <!--2 引用1處定義的car bean -->
           <ref bean="car"/>
        </property>
   </bean>
   
           

<ref>元素可以通過以下三個屬性引用容器中的其它Bean。 (1)bean:通過該屬性可以引用同一容器或父容器的Bean,這是最常見的形式。 (2)local:通過該屬性隻能引用同一配置檔案中定義的Bean,它可以利用XML解析器自動校驗引用的合法性,以便在開發編寫配置時能夠及時發現并糾正錯誤; (3)parent:引用父容器中的Bean,如<ref parent="car">的配置說明car的Bean是父容器的Bean。

為了說明子容器對父容器Bean的引用,來看一個具體的例子。假設有兩個配置檔案:beans1.xml 和beans2.xml, 其中beans.xml被父容器加載,其配置内容如下: beans1.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:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
           
           <!--1 在父容器定義的bean -->
           <bean id="car" class="com.spring.model.Car">
              <property name="brand">
                 <value>紅旗</value>
              </property>
              <property name="color" value="紅色"/>
              <property name="maxSpeed" value="200"/>
           </bean>
</beans>
           

beans2.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:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
           
    <!--該bean和父容器的car bean具有相同的id-->
           <bean id="car" class="com.spring.model.Car">
              <property name="brand">
                 <value>白旗CAR</value>
              </property>
              <property name="color" value="紅色"/>
              <property name="maxSpeed" value="200"/>
           </bean>        
           
      <bean id="boss" class="com.spring.model.Boss">
        <property name="car">
           <!-- 引用父容器的car,而非beans2.xml定義的car ,如果采用<ref bean="car" 則會引用本容器的car/>  -->
           <ref parent="car"/>
        </property>
      </bean>
</beans>
           

在beans1.xml中定義了一個car bean,在beans2.xml也定義了一個car Bean。分别通過父子容器加載beans1.xml和beans2.xml,beans2.xml中的boss通過<ref parent="car">将引用到父容器中的car. 下面是分别和父子容器加載beans1.xml和beans2.xml配置檔案的代碼:

@Test  
	public void test1(){
	 //父容器
      ApplicationContext pFactory=new ClassPathXmlApplicationContext("beans1.xml");	 
     //指定pFactory為該容器的父容器
      ApplicationContext factory=new ClassPathXmlApplicationContext(new String[]{"beans2.xml"},pFactory);
       
      Boss boss=(Boss) factory.getBean("boss");
      System.out.println(boss.getCar().getBrand());

	}
           

運作後結果如下:

紅旗
           

内部Bean

   如果car bean隻被Boss bean引用,而不會被容器中任何其它的bean引用,則可以将car以内部bean的方式注入到Boss中。

<bean id="boss" class="com.spring.model.Boss">
        <property name="car">
           <bean  class="com.spring.model.Car">
                <property name="maxSpeed" value="200"/>
                <property name="color" value="白色"/>
           </bean>
        </property>
      </bean>
           

内部bean和JAVA代碼中匿名内部類很相似,即沒有名字,也不能被其它bean引用,隻能在聲明處為外部bean提供執行個體注入。 内部bean即使提供了id、name、scope屬性,也會被忽略,scope預設為prototype類型.

null值

<property name="barnd">
           <value><null/> </value>
        </property>
           

級聯屬性

和Struts、Hibernate等架構一樣,Spring支援級聯屬性的配置。假設我們在定義Boss時直接為Car的屬性提供注入值,則可以采取以下的配置方式:

<bean id="boss2" class="com.spring.model.Boss">
        <!-- 以原點的方式定義級别屬性 -->
         <property name="car.brand" value="吉利Ct50"/>
      </bean>
           

按照上面的配置,Spring将調用Boss.getCar.setBaran("吉利Ct50"),方法進行屬性的注入操作。 Spring 沒有對級聯屬性的層級數進行限制,隻要配置的Bean擁有對應于級聯屬性的類結構,就可以配置任意層級的級聯屬性,如<property name="car.wheel.brand" value="雙星" />定義了具有三級結構的級聯屬性。

集合類型屬性

java.util包中的集合類是最常用的資料結構類型,主要包括List、Set、Map、Properties,Spring為這些集合類型屬性配置了專門的配置元素标簽。    List 我們為Boss類添加一個List類型的favourites屬性:

package com.spring.model;

import java.util.ArrayList;
import java.util.List;

public class Boss {
 
private List favourites=new ArrayList();
   
public List getFavourites() {
	return favourites;
}
public void setFavourites(List favourites) {
	this.favourites = favourites;
}}
           

對應Spring 中的配置片段如下所示:

<bean id="boss" class="com.spring.model.Boss">
           <property name="favourites">
                <list>
                    <value>看報</value>
                    <value>賽車</value>
                    <value>高爾夫</value>
                </list>
            </property>
      </bean>
           

List屬性既可以通過<value>注入字元串,也可以通過<ref>注入容器中其它的Bean. Set 如果Boss的favourites屬性時java.util.set.,則采用如下的配置方式:

<bean id="boss" class="com.spring.model.Boss">
           <property name="favourites">
                <set>
                    <value>看報</value>
                    <value>賽車</value>
                    <value>高爾夫</value>
                </set>
            </property>
      </bean>
           

Map 下面我們為Boss添加一個Map類型的jobs屬性:

package com.spring.model;

import java.util.HashMap;
import java.util.Map;

public class Boss {
	private Map jobs=new HashMap();

	public Map getJobs() {
		return jobs;
	}

	public void setJobs(Map jobs) {
		this.jobs = jobs;
	}
	
}
           

在配置檔案中,可以通過如下方式為jobs屬性提供配置值:

<bean id="boss" class="com.spring.model.Boss">
           <property name="jobs">
               <map>
                  <!-- Map 第一個元素 -->
                   <entry>
                       <key><value>AM</value></key>
                       <value>會見客戶</value>
                   </entry>
                   <!-- Map第二個元素 -->
                   <entry>
                       <key><value>PM</value></key>
                       <value>公司内部會議</value>
                   </entry>
               </map>
           </property>
      </bean>
           

假設某一Map元素的鍵和值都是對象,則可以采取以下的配置方式:

<entry>
                       <key><ref bean="keyBean"/> </key>
                       <ref bean="valueBean"/>
                   </entry>
           

Properties Properties類型其實可以看成是Map類型的特例。Map元素的鍵和值可以為任何類型的對象,而Properties屬性的鍵和值都隻能是字元串,我們為Boss添加一個Properties類型的mail屬性:

package com.spring.model;

import java.util.Properties;

public class Boss {
  private Properties mails=new Properties();

public Properties getMails() {
	return mails;
}

public void setMails(Properties mails) {
	this.mails = mails;
}
	
}
           

下面的配置片段為mails提供了配置:

<bean id="boss" class="com.spring.model.Boss">
           <property name="mails">
               <props>
                  <prop key="jobMail">[email protected]</prop>
                  <prop key="lifeMail">[email protected]</prop>
               </props>
           </property>
      </bean>
           

因為Properties鍵值對隻能是字元串,是以其配置比Map的配置要簡單一些,注意值的配置沒有<value>子元素标簽.

強類型集合

下面Boss類的jobTime屬性采用強類型的Map類型:元素的鍵為String類型;而值為Integer類型。

package com.spring.model;

import java.util.HashMap;
import java.util.Map;

public class Boss {  
	private Map<String,Integer> jobTime =new HashMap<String, Integer>();

	public Map<String, Integer> getJobTime() {
		return jobTime;
	}

	public void setJobTime(Map<String, Integer> jobTime) {
		this.jobTime = jobTime;
	}
}
           

在Spring中的配置和非強類型集合相同:

<bean id="boss" class="com.spring.model.Boss">
           <property name="jobTime">
                <map>
                   <entry>
                       <key> <value>會見客戶</value></key>
                       <value>124</value>
                   </entry>  
                </map>
           </property>
      </bean>
           

但Spring 容器在注入強類型集合時,會判斷元素的類型,将設定值轉換為對應的資料類型。如上面代碼中的設定項124将被轉換為Integer類型.

集合合并

Spring2.0新增了集合合并的功能,允許子<bean>繼承父<bean>中配置的同名屬性值合并起來作為最終bean的屬性值。

<?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:p="http://www.springframework.org/schema/p" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
        
      <!-- 父bean -->   
      <bean id="parentBoss" abstract="true" class="com.spring.model.Boss">
              <property name="favorites">
                  <set>
                      <value>看報</value>
                      <value>賽車</value>
                      <value>高爾夫</value>
                  </set>
              </property>        
      </bean>
      
      <!-- 子bean -->
       <bean id="childBoss" class="com.spring.model.Boss" parent="parentBoss">
              <property name="favorites">
                  <set merge="true">
                      <value>爬山</value>
                      <value>遊泳</value>
                  </set>
              </property>        
      </bean>
</beans>
           

在代碼清單中,通過merge="true"屬性指定子<bean>和父<bean>中的同名屬性值進行合并,即子<bean>的favourites元素将最終擁有5個元素。如果設定merge="false",則不會和父<bean>同名集合屬性進行合并,即子Bean的favourites屬性集合隻有兩個元素.

@Test 
	public void test2(){
	     ApplicationContext ctx=new ClassPathXmlApplicationContext("beans2.xml");	 
	     Boss boss=(Boss) ctx.getBean("childBoss");
	     Set set=boss.getFavorites();
	     System.out.println(set);
	}
           

運作後結果如下:

[看報, 賽車, 高爾夫, 爬山, 遊泳]