在上一章中,我們介紹了控制反轉(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中的實現
- 在通過IOC容器讀取Bean的實例之前,需要先將IOC容器本身實例化。
- 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容器中是單例的,容器實例化完成時都已經創建準備好。
- IoC容器在創建這個組件的時候,(Property標籤的方法)會利用setter方法為JavaBean屬性賦值。
- 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>
通過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>
第二種方式非常費力,通常我們都採用第一種方式進行賦值。
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>,
1、數組和List
配置java.util.List類型的屬性,需要指定<list>標籤,在標籤裡包含一些元素。這些標籤可以通過<value>指定簡單的常量值,通過指定對其他Bean的引用。通過<bean>指定內置bean定義。通過<null>指定空元素。甚至可以內嵌其他集合。/<bean>/<value>/<list>
數組的定義和List一樣,都使用<list>元素。/<list>
配置java.util.Set需要使用
<code> <bean>
<property>
/<bean>
<bean>
<property>
<list>
<bean>
/<list>
/<property>
/<bean>/<code>
2、Map
Java.util.Map通過
必須在
因為鍵和值的類型沒有限制,所以可以自由地為它們指定<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>
/<code>
<entry>
<entry>
<entry>
<entry>
<bean>
<property>
/<bean>
/<entry>
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>
閱讀更多 大數據漫路求索 的文章