第二章 IoC容器和Bean配置

在上一章中,我們介紹了控制反轉(IoC)的原理,IoC也稱為依賴注入(DI)。在Spring中,構成Application主幹並由Spring IoC容器管理的對象稱之為beans。bean是一個對象,它是由Spring IoC容器實例化,組裝和管理。Beans及其之間的依賴關係,保存在容器使用的configuration元數據中。


1 IoC容器的概述

接口org.springframework.context.ApplicationContext表示IoC容器,負責實例化,配置和組裝Beans對象。容器通過讀取configuration元數據獲取有關對象實例化,配置和組裝指令。configuration元數據以Java code,XML和Java annotations表示。


1.1 IoC容器在Spring中的實現

  1. 在通過IOC容器讀取Bean的實例之前,需要先將IOC容器本身實例化。
  2. Spring提供了IOC容器的兩種實現方式。BeanFactory:IOC容器的基本實現,是Spring內部的基礎設施,是面向Spring本身的,不是提供給開發人員使用的。ApplicationContext:BeanFactory的子接口,提供了更多高級特性。面向Spring的使用者,幾乎所有場合都使用ApplicationContext而不是底層的BeanFactory。


ApplicationContext接口的實現類有下面兩個:

  • ClassPathXmlApplicationContext:對應類路徑下的XML格式的配置文件。
  • FileSystemXmlApplicationContext:對應文件系統中的XML格式的配置文件。
  • 在初始化時,就創建的單例bean,也可以通過配置的方式指定創建的bean是多實例的。


ConfigurableApplicationContext

  • 是ApplicationContext的子接口,包含一些擴展方法
  • refresh()和close()讓ApplicationContext具有啟動、關閉和刷新上下文的能力。


WebApplicationContext

  • 專門為WEB應用而準備的,它允許從相對於WEB根目錄的路徑中完成初始化工作


1.2 配置元數據

Spring IoC 容器使用一種 configuration 元數據形式;通過configuration元數據,告訴Spring容器在application中實例化,配置和組裝對象。

Configuration元數據通常使用簡單的XML格式提供,另外在Spring容器中使用其他形式的元數據信息,也可以使用下面的方式提供:

  • annotation-based configuration:在Spring2.5以後引入的元數據配置。
  • Java-based configuration:從Spring3.0開始,Spring JavaConfig 項目提供的許多 features 成為核心 Spring Framework 的一部分。因此,您可以使用 Java 而不是 XML files 定義 application classes 外部的 beans。要使用這些新的 features,請參閱@Configuration,@Bean,@Import和@DependsOn 註釋。

Spring configuration 包含至少一個 bean定義。 XML-based configuration元數據顯示這些 beans 在 top-level <beans>元素內配置為<bean>元素。 Java configuration 通常在@Configuration class 中使用@Bean帶註釋的方法。


XML-based configuration 元數據的基本結構

<code>
<beans>       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


   <bean>
       
   /<bean>
   <bean>
       
   /<bean>
   <bean>
       
   /<bean>
   <bean>
       
   /<bean>

/<beans>/<code>

id屬性是一個 string,用於標識單個 bean 定義。 class屬性定義 bean 的類型並使用完全限定的類名。


1.3 容器實例化

實例化 Spring IoC 容器非常簡單。通過構造函數ClassPathXmlApplicationContext,加載classpath路徑中的xml的配置文件,就可以實現IoC容器的實例化。

<code>ApplicationContext bean = new ClassPathXmlApplicationContext("applicationContext.xml");/<code>


  • 容器中對象的創建,實在容器實例化完成的時候就已經創建好了。
第二章 IoC容器和Bean配置

  • 同一個組件在IoC容器中是單例的,容器實例化完成時都已經創建準備好。
第二章 IoC容器和Bean配置

  • IoC容器在創建這個組件的時候,(Property標籤的方法)會利用setter方法為JavaBean屬性賦值。
第二章 IoC容器和Bean配置

  • JavaBean的屬性名是由getter、setter方面的屬性名決定的;set後面那一串字符,首字母小寫就是JavaBean的屬性名。

2 Bean基本配置案例

2.1 根據bean的類型從IoC容器中獲取bean的實例

如果IoC容器中,某個類型的Bean有多個,查找久會報錯。

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.bigdata.bean.Student' available: expected single matching bean but found 2: student,student02

通過類型查找的好處就是,不用做類型轉換。

<code>    /**
    * 根據bean的類型從IoC容器中獲取bean的實例
    */
   @Test
   public void testIoCBeanType() {

       Student bean = ioc.getBean(Student.class);
       System.out.println(bean);
  }/<code>


可以通過使用ID名+類型的方式,解決某個Bean有多個,調用報錯的問題。

<code>    /**
    * 根據bean的類型從IoC容器中獲取bean的實例
    */
   @Test
   public void testIoCBeanType() {

       Student bean = ioc.getBean("student",Student.class);
       System.out.println(bean);
  }/<code>


2.2 通過構造器為bean的屬性賦值

修改Student.java

<code>    public Student(String stuId, String stuName, Integer age) {
       super();
       this.stuId = stuId;
       this.stuName = stuName;
       this.age = age;
       System.out.println("有參構造器。。。。");
  }/<code>


在applicationContext.xml文件中添加如下內容

<code>    <bean>
       
       
       <constructor-arg>
       <constructor-arg>
       <constructor-arg>
   /<bean>/<code>


修改測試類

<code>    /**
    * 通過構造器為bean的屬性賦值
    */
   @Test
   public void testIoCBeanConstructor() {

       Student bean = ioc.getBean("student03",Student.class);
       System.out.println(bean);
  }/<code>


第二章 IoC容器和Bean配置

通過index,type屬性,來構造對象屬性的值。

在applicationContext.xml添加如下內容

<code>    <bean>
       
       <constructor-arg>
       <constructor-arg>
       <constructor-arg>
   /<bean>/<code>


修改測試類,測試結果是一致的。

<code>    /**
    * 通過構造器為bean的屬性賦值
    */
   @Test
   public void testIoCBeanConstructor() {

//       Student bean = ioc.getBean("student03",Student.class);
//       System.out.println(bean);
       Student student04 = ioc.getBean("student04", Student.class);
       System.out.println(student04);
  }/<code>
第二章 IoC容器和Bean配置

第二種方式非常費力,通常我們都採用第一種方式進行賦值。

2.3 通過p名稱空間為bean賦值

通過名稱空間的形式,在xml文件中,名稱空間是用來防止標籤重複的。為了簡化XML文件的配置,越來越多的XML文件採用屬性而非子元素配置信息。

Spring從2.5版本開始引入了一個新的p命名空間,可以通過<bean>元素屬性的方式配置Bean的屬性。/<bean>

使用p命名空間後,基於XML的配置方式將進一步簡化。

<code><beans>       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   
<bean>        p:stuId="1004" p:stuName="宋江" p:age="45">
   /<bean>/<beans>/<code>


修改測試類

<code>    /**
    * 通過p名稱空間為bean賦值
    */
   @Test
   public void testIoCBeanPtag() {

       Student student05 = ioc.getBean("student05", Student.class);
       System.out.println(student05);
  }/<code>


2.4 可以使用的值

1、字面量

  • 可以使用字符串表示的值,可以通過value屬性或value子節點的方式指定
  • 基本數據類型及其封裝類、String等類型都可以採取字面值注入的方式
  • 若字面值中包含特殊字符,可以使用把字面值包裹起來


2、null值

修改applicationContext2.xml

<code>    <bean>
       
       <property>
       <property>
       
       <property>
           <null>
       /<property>
   /<bean>/<code>


<code>    <bean>
       <property>

       <property>
   /<bean>
   <bean>
       
       <property>
   /<bean>/<code>


4、內部bean

當bean實例僅僅給一個特定的屬性使用時,可以將其聲明為內部bean。內部bean聲明直接包含在<property>或<constructor-arg>元素裡,不需要設置任何id或name屬性/<constructor-arg>/<property>

內部bean不能使用在任何其他地方

<code>    <bean>
       
       <property>
           <bean>
               <property>
           /<bean>
       /<property>
   /<bean>/<code>


2.5 集合屬性

在Spring中可以通過一組內置的XML標籤來配置集合屬性,例如:<list>,/<list>

1、數組和List

配置java.util.List類型的屬性,需要指定<list>標籤,在標籤裡包含一些元素。這些標籤可以通過<value>指定簡單的常量值,通過指定對其他Bean的引用。通過<bean>指定內置bean定義。通過<null>指定空元素。甚至可以內嵌其他集合。/<bean>/<value>/<list>

數組的定義和List一樣,都使用<list>元素。/<list>

配置java.util.Set需要使用標籤,定義的方法與List一樣。

<code>    <bean>
       <property>
   /<bean>
   <bean>
       
       <property>
           
           <list>
               
               <bean>

               
               
           /<list>
       /<property>
/<bean>/<code>


2、Map

Java.util.Map通過標籤定義,標籤裡可以使用多個<entry>作為子標籤。每個條目包含一個鍵和一個值。/<entry>

必須在標籤裡定義鍵。

因為鍵和值的類型沒有限制,所以可以自由地為它們指定<value>、、<bean>或<null>元素。/<bean>/<value>

可以將Map的鍵和值作為<entry>的屬性定義:簡單常量使用key和value來定義;bean引用通過key-ref和value-ref屬性定義。/<entry>

<code>    <bean>
       <property>
   /<bean>
   <bean>
       
       <property>
           
           
               
               <entry>
               <entry>
               <entry>
               <entry>
                   <bean>

                       <property>
                   /<bean>
               /<entry>
           

       /<property>
   /<bean>/<code>


3、Properties

使用<props>定義java.util.Properties,該標籤使用多個<prop>作為子標籤。每個<prop>標籤必須定義key屬性/<prop>/<prop>/<props>

<code>    <bean>

       <property>
           
           <props>
               
               <prop>root/<prop>
               <prop>root/<prop>
           /<props>
       /<property>
   /<bean>/<code>


4、集合類型的bean

如果只能將集合對象配置在某個bean內部,則這個集合的配置將不能重用。我們需要將集合bean的配置拿到外面,供其他bean引用。

配置集合類型的bean需要引入util名稱空間

<code>    
   <bean>
       <property>
   /<bean>

   
   
       
       
       <entry>
       <entry>
       <entry>
       <entry>
           <bean>
               <property>
           /<bean>
       /<entry>
   
/<code>


5、級聯屬性

所謂級聯屬性,就是屬性的屬性。在修改屬性時,原來的bean屬性值可能會被修改。

<code>    
   <bean>
       
       <property>

       <property>
   /<bean>/<code>


<code>   /**
    * 測試級聯屬性類型
    */
   @Test
   public void testCascade() {
       Person person04 = ioc.getBean("person04", Person.class);
       Car car01 = ioc.getBean("car01", Car.class);

       // 容器中的car:Car{carName='寶馬', price=900000.0}
       System.out.println("容器中的car:" +car01);

       // Person中的car:Car{carName='寶馬', price=900000.0}
       System.out.println("Person中的car:" +person04.getCar());
  }/<code>



分享到:


相關文章: