spring之BeanFactory

 BeanFactory

BeanFactory 是 Spring 的「心臟」。它就是 Spring IoC 容器的真面目。Spring 使用 BeanFactory 來實例化、配置和管理 Bean。可是,在大多數狀況咱們並不直接使用 BeanFactory,而是使用 ApplicationContext。它也是 BeanFactory 的一個實現,可是它添加了一系列「框架」的特徵,好比:國際化支持、資源訪問、事件傳播等。ApplicationContext 咱們將在後面章節中介紹。java

BeanFactory 實際上是一個接口-org.springframework.beans.factory.BeanFactory,它能夠配置和管理幾乎全部的 Java 類。固然,具體的工做是由實現 BeanFactory 接口的實現類完成。咱們最經常使用的 BeanFactory 實現是 org.springframework.beans.factory.xml.XmlBeanFactory。它從 XML 文件中讀取 Bean 的定義信息。當 BeanFactory 被建立時,Spring 驗證每一個 Bean 的配置。固然,要等 Bean 建立以後才能設置 Bean 的屬性。單例(Singleton)Bean 在啓動時就會被 BeanFactory 實例化,其它的 Bean 在請求時建立。根據 BeanFactory 的 Java 文檔(Javadocs)介紹,「Bean 定義的持久化方式沒有任何的限制:LDAP、RDBMS、XML、屬性文件,等等」。如今 Spring 已提供了 XML 文件和屬性文件的實現。無疑,XML 文件是定義 Bean 的最佳方式。spring

BeanFactory 是初始化 Bean 和調用它們生命週期方法的「吃苦耐勞者」。注意,BeanFactory 只能管理單例(Singleton)Bean 的生命週期。它不能管理原型(prototype,非單例)Bean 的生命週期。這是由於原型 Bean 實例被建立以後便被傳給了客戶端,容器失去了對它們的引用。app

spring的IOC容器可以幫咱們自動new對象,對象交給spring管以後咱們不用本身手動去new對象了。那麼它的原理是什麼呢?是怎麼實現的呢?下面我來簡單的模擬一下spring的機制,相信看完以後就會對spring的原理有必定的瞭解。spring使用BeanFactory來實例化、配置和管理對象,可是它只是一個接口,裏面有一個getBean()方法。咱們通常都不直接用BeanFactory,而是用它的實現類ApplicationContext,這個類會自動解析咱們配置的applicationContext.xml,而後根據咱們配置的bean來new對象,將new好的對象放進一個Map中,鍵就是咱們bean的id,值就是new的對象。

  首先咱們創建一個BeanFactory接口框架

1 package com.spring;
2 
3 public interface BeanFactory {
4     Object getBean(String id);
5 }

  而後創建一個BeanFactory的實現類ClassPathXmlApplicationContext.javadom

複製代碼
 1 package com.spring;
 2 
 3 import java.util.HashMap;
 4 import java.util.List;
 5 import java.util.Map;
 6 
 7 import org.dom4j.Document;
 8 import org.dom4j.DocumentException;
 9 import org.dom4j.Element;
10 import org.dom4j.io.SAXReader;
11 
12 
13 public class ClassPathXmlApplicationContext implements BeanFactory {
14     private Map<String, Object> beans = new HashMap<String, Object>();
15     public ClassPathXmlApplicationContext(String fileName) throws Exception{
16         SAXReader reader = new SAXReader();
17         Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream(fileName));
18         List<Element> elements = document.selectNodes("/beans/bean");
19         for (Element e : elements) {
20             String id = e.attributeValue("id");
21             String value = e.attributeValue("class");
22             Object o = Class.forName(value).newInstance();
23             beans.put(id, o);
24         }
25     }
26     
27     public Object getBean(String id) {
28         return beans.get(id);
29     }
30 
31 }
複製代碼

  而後配置applicationContext.xml函數

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans>
3     <bean id="c" class="com.spring.Car"></bean>
4      <bean id="p" class="com.spring.Plane"></bean>
5 </beans>

建立類的時候順便演示一下工廠模式,其實BeanFactory它也是一種工廠模式的。post

1 package com.spring;
2 
3 public interface Moveable {
4     void run();
5 }
複製代碼
1 package com.spring;
2 
3 public class Car implements Moveable{
4     
5     public void run(){
6         System.out.println("拖着四個輪子滿街跑car·····");
7     }
8 }
複製代碼
複製代碼
1 package com.spring;
2 
3 public class Plane implements Moveable{
4 
5     public void run() {
6         System.out.println("拖着翅膀天空飛plane......");
7     }
8     
9 }
複製代碼

 

如今來看一看效果吧,寫一個類測試一下:測試

複製代碼
 1 package com.spring;
 2 
 3 import org.dom4j.DocumentException;
 4 
 5 public class Test {
 6 
 7     /**
 8      * @param args
 9      * @throws DocumentException 
10      */
11     public static void main(String[] args) throws Exception {
12         BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
13         Object o = factory.getBean("c");
14         Moveable m = (Moveable)o;
15         m.run();
16     }
17 
18 }
複製代碼

因爲Map容器裏面保存的是Object類型,因此經過getBean()方法取出來的對象要強制類型轉換。this

BeanFactory 管理 Bean(組件)的生命週期

下圖描述了 Bean 的生命週期。它是由 IoC 容器控制。IoC 容器定義 Bean 操做的規則,即 Bean 的定義(BeanDefinition)。Bean 的定義包含了 BeanFactory 在建立 Bean 實例時須要的全部信息。BeanFactory 首先經過構造函數建立一個 Bean 實例,以後它會執行 Bean 實例的一系列以前初始化動做,初始化結束 Bean 將進入準備就緒(ready)狀態,這時應用程序就能夠獲取這些 Bean 實例了。最後,當你銷燬單例(Singleton)Bean 時,它會調用相應的銷燬方法,結束 Bean 實例的生命週期。spa

Bean 的定義

前面的用戶註冊的例子中,咱們已經使用 Spring 定義了一個用戶持久化類:

<bean id="userDao" class="com.dev.spring.simple.MemoryUserDao"/>
這是一個最簡單的 Bean 定義。它相似於調用了語句:
MemoryUserDao userDao = new MemoryUserDao()。
id屬性必須是一個有效的 XML ID,這意味着它在整個 XML 文檔中必須惟一。它是一個 Bean 的「終身代號(9527)」。同時你也能夠用 name 屬性爲 Bean 定義一個或多個別名(用逗號或空格分開多個別名)。name 屬性容許出現任意非法的 XML 字母。例如:
<bean id="userDao" name="userDao*_1, userDao*_2"

class="com.dev.spring.simple.MemoryUserDao"/>。

class屬性定義了這個 Bean 的全限定類名(包名+類名)。Spring 能管理幾乎全部的 Java 類。通常狀況,這個 Java 類會有一個默認的構造函數,用set方法設置依賴的屬性。

Bean 元素出了上面的兩個屬性以外,還有不少其它屬性。說明以下:

複製代碼
<bean

    id="beanId"(1)

    name="beanName"(2)

    class="beanClass"(3)

    parent="parentBean"(4)

    abstract="true | false"(5)

    singleton="true | false"(6)

    lazy-init="true | false | default"(7)

    autowire="no | byName | byType | constructor | autodetect | default"(8)

    dependency-check = "none | objects | simple | all | default"(9)

    depends-on="dependsOnBean"(10)

    init-method="method"(11)

    destroy-method="method"(12)

    factory-method="method"(13)

    factory-bean="bean">(14)

</bean>
複製代碼
複製代碼
(1).id: Bean 的惟一標識名。它必須是合法的 XML ID,在整個 XML 文檔中惟一。

(2).name: 用來爲 id 建立一個或多個別名。它能夠是任意的字母符合。多個別名之間用逗號或空格分開。

(3).class: 用來定義類的全限定名(包名+類名)。只有子類 Bean 不用定義該屬性。

(4).parent: 子類 Bean 定義它所引用它的父類 Bean。這時前面的 class 屬性失效。子類 Bean 會繼承父類 Bean 的全部屬性,子類 Bean 也能夠覆蓋父類 Bean 的屬性。注意:子類 Bean 和父類 Bean 是同一個 Java 類。

(5).abstract(默認爲」false」):用來定義 Bean 是否爲抽象 Bean。它表示這個 Bean 將不會被實例化,通常用於父類 Bean,由於父類 Bean 主要是供子類 Bean 繼承使用。

(6).singleton(默認爲「true」):定義 Bean 是不是 Singleton(單例)。若是設爲「true」,則在 BeanFactory 做用範圍內,只維護此 Bean 的一個實例。若是設爲「flase」,Bean將是 Prototype(原型)狀態,BeanFactory 將爲每次 Bean 請求建立一個新的 Bean 實例。

(7).lazy-init(默認爲「default」):用來定義這個 Bean 是否實現懶初始化。若是爲「true」,它將在 BeanFactory 啓動時初始化全部的 Singleton Bean。反之,若是爲「false」,它只在 Bean 請求時纔開始建立 Singleton Bean。

(8).autowire(自動裝配,默認爲「default」):它定義了 Bean 的自動裝載方式。

「no」:不使用自動裝配功能。
「byName」:經過 Bean 的屬性名實現自動裝配。
「byType」:經過 Bean 的類型實現自動裝配。
「constructor」:相似於 byType,但它是用於構造函數的參數的自動組裝。
「autodetect」:經過 Bean 類的檢討機制(introspection)決定是使用「constructor」仍是使用「byType」。
(9).dependency-check(依賴檢查,默認爲「default」):它用來確保 Bean 組件經過 JavaBean 描述的因此依賴關係都獲得知足。在與自動裝配功能一塊兒使用時,它特別有用。

none:不進行依賴檢查。
objects:只作對象間依賴的檢查。
simple:只作原始類型和 String 類型依賴的檢查
all:對全部類型的依賴進行檢查。它包括了前面的 objects 和 simple。
(10).depends-on(依賴對象):這個 Bean 在初始化時依賴的對象,這個對象會在這個 Bean 初始化以前建立。

(11).init-method:用來定義 Bean 的初始化方法,它會在 Bean 組裝以後調用。它必須是一個無參數的方法。

(12).destroy-method:用來定義 Bean 的銷燬方法,它在 BeanFactory 關閉時調用。一樣,它也必須是一個無參數的方法。它只能應用於singleton Bean。

(13).factory-method:定義建立該 Bean 對象的工廠方法。它用於下面的「factory-bean」,表示這個 Bean 是經過工廠方法建立。此時,「class」屬性失效。

(14).factory-bean:定義建立該 Bean 對象的工廠類。若是使用了「factory-bean」則「class」屬性失效。(1).id: Bean 的惟一標識名。它必須是合法的 XML ID,在整個 XML 文檔中惟一。

(2).name: 用來爲 id 建立一個或多個別名。它能夠是任意的字母符合。多個別名之間用逗號或空格分開。

(3).class: 用來定義類的全限定名(包名+類名)。只有子類 Bean 不用定義該屬性。

(4).parent: 子類 Bean 定義它所引用它的父類 Bean。這時前面的 class 屬性失效。子類 Bean 會繼承父類 Bean 的全部屬性,子類 Bean 也能夠覆蓋父類 Bean 的屬性。注意:子類 Bean 和父類 Bean 是同一個 Java 類。

(5).abstract(默認爲」false」):用來定義 Bean 是否爲抽象 Bean。它表示這個 Bean 將不會被實例化,通常用於父類 Bean,由於父類 Bean 主要是供子類 Bean 繼承使用。

(6).singleton(默認爲「true」):定義 Bean 是不是 Singleton(單例)。若是設爲「true」,則在 BeanFactory 做用範圍內,只維護此 Bean 的一個實例。若是設爲「flase」,Bean將是 Prototype(原型)狀態,BeanFactory 將爲每次 Bean 請求建立一個新的 Bean 實例。

(7).lazy-init(默認爲「default」):用來定義這個 Bean 是否實現懶初始化。若是爲「true」,它將在 BeanFactory 啓動時初始化全部的 Singleton Bean。反之,若是爲「false」,它只在 Bean 請求時纔開始建立 Singleton Bean。

(8).autowire(自動裝配,默認爲「default」):它定義了 Bean 的自動裝載方式。

「no」:不使用自動裝配功能。
「byName」:經過 Bean 的屬性名實現自動裝配。
「byType」:經過 Bean 的類型實現自動裝配。
「constructor」:相似於 byType,但它是用於構造函數的參數的自動組裝。
「autodetect」:經過 Bean 類的檢討機制(introspection)決定是使用「constructor」仍是使用「byType」。
(9).dependency-check(依賴檢查,默認爲「default」):它用來確保 Bean 組件經過 JavaBean 描述的因此依賴關係都獲得知足。在與自動裝配功能一塊兒使用時,它特別有用。

none:不進行依賴檢查。
objects:只作對象間依賴的檢查。
simple:只作原始類型和 String 類型依賴的檢查
all:對全部類型的依賴進行檢查。它包括了前面的 objects 和 simple。
(10).depends-on(依賴對象):這個 Bean 在初始化時依賴的對象,這個對象會在這個 Bean 初始化以前建立。

(11).init-method:用來定義 Bean 的初始化方法,它會在 Bean 組裝以後調用。它必須是一個無參數的方法。

(12).destroy-method:用來定義 Bean 的銷燬方法,它在 BeanFactory 關閉時調用。一樣,它也必須是一個無參數的方法。它只能應用於singleton Bean。

(13).factory-method:定義建立該 Bean 對象的工廠方法。它用於下面的「factory-bean」,表示這個 Bean 是經過工廠方法建立。此時,「class」屬性失效。

(14).factory-bean:定義建立該 Bean 對象的工廠類。若是使用了「factory-bean」則「class」屬性失效。
複製代碼
相關文章
相關標籤/搜索