Spring_bean的作用域與生命週期

  在Spring中,那些組成應用程序的主體及由Spring IoC容器所管理的對象,被稱之爲bean。簡單地講,bean就是由IOC容器初始化、裝配及管理的對象,除此之外,bean就與應用程序中的其他對象沒有什麼區別了。而bean的定義以及bean相互間的依賴關係將通過配置元數據來描述。

1、bean的作用域

  在Spring中,可以在<bean>元素的scope屬性裏設置bean的作用域,以決定這個bean是單實例還是多實例的。

  默認情況下,Spirng只爲每個在IOC容器裏聲明的bean創建唯一一個實例,整個IOC容器範圍內都能共享該實例。所有後續的getBean()調用和bean引用都將返回這個唯一的bean實例。該作用域被稱爲singleton,它是所有bean的默認作用域。

  創建一個bean定義,其實質是用該bean定義對應的類來創建真正實例的“配方”。把bean定義看成一個配方很有意義,它與class很類似,只根據一張“處方”就可以創建多個實例。不僅可以控制注入到對象中的各種依賴和配置值,還可以控制該對象的作用域。這樣可以靈活選擇所建對象的作用域,而不必在Hava Class級定義作用域。Spring Framework支持五種作用域,如下表所示:

類別 說明
singleton 在SpringIOC容器中僅存一個Bean實例,Bean以單實例的方式存在
prototype 每次調用getBean()時都會返回一個新的實例
request 每次HTTP請求都會創建一個新的Bean,該作用域僅適用於WebApplicationContext環境
session 同一個HTTP Session共享一個Bean,不同的HTTP Session使用不同的Bean。該作用域僅適用於WebApplicationContext環境
globalSession 一般用於Portlet應用環境,該作用域僅適用於WebApplicationContext環境

在五種作用域中,request、session、global session三種作用域僅在基於web的應用中使用。

(1) 當一個bean的作用域爲Singleton,那麼Spring IOC容器中只會存在一個共享的bean實例,並且所有對bean的請求,只要id與bean定義相匹配,則只會返回bean的同一實例。Singleton是單例類型,就是在創建起容器時就同時自動創建了一個bean的對象,不管你是否使用,他都存在了,每次獲取到的對象都是同一個對象。注意,Singleton作用域是Spring中的缺省作用域。可以並不用配置,如果要在XML中將bean定義成singleton可以這樣配置:

<bean id="ServiceImpl" class="com.service.ServiceImpl" scope="singleton" />

(2) 當一個bean的作用域爲Prototype,表示一個bean定義對應多個對象實例。Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調用容器的getBean()方法)時都會創建一個新的bean實例。Prototype是原型類型,它在我們創建容器的時候並沒有實例化,而是當我們獲取bean的時候纔會去創建一個對象,而且我們每次獲取到的對象都不是同一個對象。配置XML文件時可以這樣配置:

<bean id="pring" class="com.spring.Defaultpring" scope="prototype" />

(3) 當一個bean的作用域爲Request,表示在一次HTTP請求中,一個bean定義對應一個實例;即每個HTTP請求都會有各自的bean實例,它們依據某個bean定義創建而成。該作用域僅在基於web的Spring ApplicationContext情形下有效。看如下實例:

<bean id="login" class="com.spring.Login" scope="request" />

針對每次HTTP請求,Spring容器會根據login bean的定義創建一個全新的Login bean實例,且該login bean實例僅在當前HTTP request內有效,。當處理請求結束,request作用域的bean實例將被銷燬。
 
(4) 當一個bean的作用域爲Session,表示在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。看如下實例:

<bean id="login" class="com.spring.Login" scope="session" />

針對某個HTTP Session,Spring容器會根據login bean定義創建一個全新的login bean實例,且該login bean僅在當前HTTP Session內有效。

(5) 當一個bean的作用域爲Global Session,表示在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基於web的Spring ApplicationContext情形下有效。看如下實例:

<bean id="login" class="com.spring.Login" scope="globalSession" />

global session作用域類似於標準的HTTP Session作用域,不過僅僅在基於portlet的web應用中才有意義。

2、繼續看看bean的生命週期

1)Spring IOC容器可以管理bean的生命週期,Spring允許在bean生命週期內特定的時間點執行指定的任務。
2)Spring IOC容器對普通bean的生命週期進行管理的過程:

① 通過構造器或工廠方法創建bean實例。
② 爲bean的屬性設置值和對其他bean的引用。
③ 調用bean的初始化方法。
④ 使用bean。
⑤ 當容器關閉時,調用bean的銷燬方法。

3)在配置bean時,通過init-method和destroy-method屬性爲bean指定初始化和銷燬方法。

  Spring允許我們創建自己的 init 方法和 destroy 方法,只要在 Bean 的配置文件中指定 init-method 和 destroy-method 的值就可以在 Bean 初始化時和銷燬之前執行一些操作,例子如下:

public class GiraffeService {
    //通過<bean>的destroy-method屬性指定的銷燬方法
    public void destroyMethod() throws Exception {
        System.out.println("執行配置的destroy-method");
    }
    //通過<bean>的init-method屬性指定的初始化方法
    public void initMethod() throws Exception {
        System.out.println("執行配置的init-method");
    }
}

XML文件bean配置:

<bean name="giraffeService" class="com.giraffe.spring.service.GiraffeService" init-method="initMethod" destroy-method="destroyMethod">
</bean>

4)說說bean的後置處理器

① bean後置處理器允許在調用初始化方法前後對bean進行額外的處理。
② bean後置處理器對IOC容器裏的所有bean實例逐一處理,而非單一實例。
③ bean後置處理器需要實現接口:
org.springframework.beans.factory.config.BeanPostProcessor。在初始化方法被調用前後,Spring將把每個bean實例分別傳遞給上述接口的以下兩個方法:

  • postProcessBeforeInitialization(Object,Stirng):該方法會在容器中的Bean初始化之前執行。
  • postProcessAfterInitialization(Object,Stirng):該方法會在容器中的Bean初始化之後執行。

例子如下:

public class CustomerBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=" + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
        return bean;
    }
}

要將BeanPostProcessor的Bean像其他Bean一樣定義在配置文件中:

<bean class="com.giraffe.spring.service.CustomerBeanPostProcessor"/>

5) 添加bean後置處理器後bean的生命週期

① bean容器找到配置文件中 Spring Bean 的定義
② 通過構造器或工廠方法創建bean實例。
③ 爲bean的屬性設置值和對其他bean的引用。
④ 將bean實例傳遞給bean後置處理器的postProcessBeforeInialization()方法。
⑤ 如果bean實現了InitializingBean接口,執行afterPropertiesSet()方法。
⑥ 如果bean在配置文件中的定義包含init-method屬性,執行指定的方法。
⑦ 將bean實例傳遞給bean後置處理器的postProcessAfterInitialization()方法。
⑧ 使用bean。
⑨ 當要銷燬bean的時候,如果Bean實現了DisposableBean接口,執行destroy()方法。
⑩ 當要銷燬bean的時候,如果Bean在配置文件中的定義包含destroy-method屬性,執行指定的方法。

Spring Bean生命週期圖解:
在這裏插入圖片描述

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