Spring之bean的詳解

前言:對於使用Spring框架的開發人員來說,我們主要做的主要有兩件事情:①開發Bean;②配置Bean;而Spring幫我們做的就是根據配置文件來創建Bean實例,並調用Bean實例的方法來完成“依賴注入”,可以把Spring容器理解成一個大型工廠,Bean就是該工廠的產品,工廠(Spirng容器)裏能生產出來什麼樣的產品(Bean),完全取決於我們在配置文件中的配置。我們那麼今天我們就來說說關於Bean的故事。。。

容器中Bean的作用域

singleton 在整個Spring IoC 容器中,使用 singleton 定義的Bean將只有一個實例
prototype 原型模式,每次通過容器的getBean 方法獲取prototype定義的Bean 時,都將產生一個新的Bean實例
request 對於每次HTTP請求,使用request定義的Bean都將產生一個新的實例,每次HTTP請求都將產生不同的Bean實例,該作用域僅在給予web的Spring ApplicationContext情形下有效
session 對於每次HTTP Session ,使用session定義的Bean都將產生一個新實例,該作用域僅在給予web的Spring ApplicationContext情形下有效
global session 每個全局得HTTP Session對應一個Bean實例,該作用域僅在給予web的Spring ApplicationContext情形下有效

 

       比較常用的是singleton 和 prototype 兩種作用域,對於singleton作用域,每次請求該Bean都將獲得相同的實例,Spring容器負責跟蹤監視Bean實例的狀態,負責維護Bean實例的生命週期行爲,如果一個Bean被設置成prototype作用域,程序每次請求該id的Bean,Spring都會創建一個新的Bean實例,然後返回給程序,在這種情況下,Spring容器僅僅使用new 關鍵字創建Bean實例,一旦創建成功,容器Spring不再對Bean的生命週期負責,也不會維護Bean實例的狀態。

      如果不指定Bean的作用域,Spring默認使用singleton作用域。Java在常見Java實例時,需要進行內存申請,銷燬實例是,需要完成垃圾回收,這些工作都會導致系統開銷的增加。因此prototype作用域Bean 的創建銷燬代價比較大。而singleton作用域的Bean 實例一旦創建成功,可以重複使用,因此,除非必要,否則避免將Bean作用域設置成prototype。

      如果要使用 request,session,global session作用域的Bean,在配置Bean之前,還需要做少量的初始配置(將HTTP 請求banding到該提供服務的線程上,這使得具有request 和 session作用域的Bean實例能夠在後面的調用鏈中被訪問到),如果只是配置常規的作用域(singleton,prototype),則無須設置。如果Web 應用直接使用Spring MVC 作爲MVC框架,即使用SpringDispatcherServlet 或DispatcherPorlet 來攔截所有用戶請求,則無須設置,因爲DispatcherServlet 和DispatcherPorlet已經處理了所有和請求有關的額狀態處理。

當使用Spring’s DispatcherServlet 以外的Servlet 2.4 及以上規範的Web 容器時需要在“web.xml”中增加如下配置:

<listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

如果使用的是早起版本的Web容器,則該容器不支持Listener 規範,故無法使用上述配置,只能改爲Filter配置方式,配置代碼如下:

複製代碼
<filter>
        <filter-name>requestContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>requestContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>
複製代碼

 容器中Bean的生命週期

Spring可以管理singleton作用域Bean的生命週期,Spring可以精確地知道singleton域bean何時被創建,何時初始化完成,以及容器何時準備銷燬Bean實例。因爲,對於singleton作用域的Bean,客戶端的每次請求都返回同一個Bean實例,客戶端代碼不能控制Bean的銷燬,它的生命週期都在Spring的掌握之中。這麼一來,容器就可以管理實例化結束後(某些資源的申請)和銷燬之前(進行某些資源的回收)的行爲。管理Bean的生命週期行爲主要有兩個時機:注入依賴關係後,銷燬實例之前;具體的管理方法如下

Spring提供兩種方式在Bean全部屬性設置成功後執行特定行爲

     使用init-method 屬性(代碼污染小)

             在類中編寫一個方法,在屬性中指定該方法在依賴關係設置完成後自動執行。

     實現InitializingBean接口(耦合較高)

            編寫afterPropertiesSet()方法的具體實現

同理,若在Bean銷燬之前,執行特定的方法,只需要①使用 destroy-method屬性②實現DisposableBean接口(實現destroy()方法)

對於prototype作用域的Bean,Spring容器只負責Bean的創建,當容器創建實例完成後,Bean將完全交給客戶端代碼管理,容器不再負責其生命週期。每次客戶端請求prototype作用域的Bean時,Spring容器都會產生一個全新的Bean實例交個客戶端(prototype就是這麼任性),Spring容器本省也不知道自己創建了多少個實例,更無從知道這些實例什麼時候纔會被銷燬。

Spring 的 Bean 和 JavaBean比較

    1. 規範:Spring容器對Bean 沒有特殊要求,不像JavaBean 一樣遵循一些規範(爲每個屬性提供相應的setter 和 getter 方法),不過對於設值注入的Bean,一定要提供setter 方法。
    2. 作用:Spring 中的Bean 是 java 實例,java組件,它的作用幾乎無所不包,任何應用組件都被稱爲Bean,而傳統的Java應用中的JavaBean通常作爲DTO(數據傳輸對象),來封裝值對象,在各層之間傳遞數據。
    3. 生命週期:傳統的JavaBean作爲值對象傳遞,不接受任何容器管理其生命週期,Spring中的Bean有Spring管理其生命週期行爲。

Spring 的Bean繼承和java繼承的區別

    1. Spring中子Bean和父Bean可以是不同的類型,而java中的繼承子類只是父類的一種特殊類型。
    2. Spring中Bean的繼承是實例之間的關係,主要表現爲參數值的延續,而java終的繼承是類之間的關係,主要表現爲屬性,方法的延續。
    3. Spring中子Bean不可做父Bean使用,不具備多態性,java中的子類實例完全可以做父類的實例使用

Bean 實例的創建方式及依賴配置

     大多數情況下,BeanFactory 直接通過new 關鍵字調用構造器來創建Bean 實例,而class屬性指定了Bean實例的實現類。但這並不是實例化Bean的唯一方法。

創建Bean通常有以下三種方式

    1. 調用構造器創建Bean 實例
    2. 調用靜態工廠方法創建Bean
    3. 調用實例工廠方法創建Bean
    •       調用構造器創建Bean 實例     

調用構造器創建Bean實例是最常見的情況,,BeanFactory 將使用默認的構造器來創建Bean實例,該實例是個默認實例,Spring對Bean實例的所有屬性執行默認初始化,即所有基本類型的值初始化爲0或false,引用類型初始化爲null,接下來BeanFactory會根據配置文件決定依賴關係,先實例化被依賴的Bean 實例,然後爲Bean注入依賴關係,最後將一個完整的Bean實例返回給程序,該Bean實例化的所有屬性,已經由Spring容器完成了初始化。

    •       使用靜態工廠方法創建Bean

使用靜態工廠方法創建Bean實例時,class屬性也必須指定,但此時class屬性並不是指定Bean實例的實現類,而是靜態工廠類,Spring需要根據工廠類的工廠方法來創建Bean實例,除此之外,還需要使用factory-method 屬性來指定靜態工廠方法名,Spring調用靜態工廠方法(可能包含一組參數,若需要,使用<constructor-arg…/>元素傳入)返回一個Bean實例,獲得Bean實例後,Spring後面的處理步驟與採用普通方法創建Bean實例完全一樣。

使用靜態工廠方法創建Bean實例時,Spring將先解析配置文件,並根據配置文件指定的信息,通過反射調用靜態工廠類的靜態工廠方法,將該靜態工廠方法的凡湖值作爲Bean實例。在這個過程中,Spring不再負責創建Bean實例,Bean實例的創建是用戶提供的靜態工廠類負責創建的。但是Spring容器依然可以管理Bean實例的依賴關係,生命週期。

    •     使用實例工廠方法

實例工廠方法與靜態工廠方法不同:調用靜態工廠方法只需使用工廠類,調用實例工廠方法則必須使用工廠實例。採用實例工廠方法時,配置Bean實例的<bean../>元素無需class屬性,因爲Spring容器不再直接實例化該Bean,Spring容器僅僅調用實例工廠的工廠方法,工廠方法負責創建Bean實例。採用實例工廠方法創建Bean時,需要爲<bean../>元素指定如下兩個屬性:factory-bean:該屬性的值爲工廠Bean的id.factory-method:該屬性指定實例工廠的工廠方法。與靜態工廠方法相似,如果需要調用工廠方法時傳入參數,使用<constructor-arg…/>元素確定參數值。

靜態工廠方法創建實例和工廠方法創建實例的異同點

調用實例工廠方法創建Bean,必須將實例工廠配置成Bean實例。而靜態工廠方法創建Bean,則無需配置工廠Bean。

調用實例工廠方法創建Bean,必須使用factory-bean屬性確定工廠Bean。而靜態工廠方法創建Bean,則使用class 元素確定靜態工廠類。

都需要factory-method 指定相應產生Bean實例的工廠方法。

工廠方法需要參數都可以使用<constructor-art…/>元素指定參數。

本文轉自:http://www.cnblogs.com/shinubi/p/4182027.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章