一文詳解Spring中Bean的生命週期

在Spring中,Bean是最基礎的對象,一切操做都是圍繞Bean展開的。Spring是一個BOP(Bean Oriented Programming)框架,Bean在BOP中的做用就像是對象在OOP中的做用同樣。既然如此重要,那麼咱們首先須要瞭解到底什麼是Bean?java

什麼是Bean

首先,咱們來看看Spring官方文檔對於Bean的定義:web

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your applicationspring

從上面可知,咱們能夠給Bean下一個定義:Bean就是由IOC實例化、組裝、管理的一個對象websocket

Bean的生命週期

咱們須要明確的是,在這裏咱們的Bean的生命週期主要指的是singleton bean,對prototype bean來講,當用戶getBean得到prototype bean的實例後,IOC容器就再也不對當前實例進行管理,而是把管理權交由用戶,此後再getBean生成的是新的實例。對於request/session/application/websocket 這幾種scope的bean咱們在此不談。session

在不一樣的容器中,Bean的生命週期開始的時間不一樣。對於ApplicationContext來講,當容器啓動的時候,bean就已經實例化了。而對於BeanFactory來講,直到調用getBean()方法的時候才進行實例化。app

咱們知道對於普通的java對象來講,它們的生命週期就是框架

  • 實例化
  • 再也不使用的時候經過垃圾回收機制進行回收

可是對於Bean來講卻不是這樣。Bean的生命週期以下圖所示socket

對於如上這些方法,咱們能夠分紅以下幾類函數

  1. Bean自身的方法:好比構造函數、getter/setter以及init-method和destory-method所指定的方法等
  2. Bean級生命週期方法:能夠理解爲Bean類直接實現接口的方法,好比BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean、DisposableBean等方法,這些方法只對當前Bean生效
  3. 容器級的方法(BeanPostProcessor一系列接口):主要是後處理器方法,好比上圖的InstantiationAwareBeanPostProcessor、BeanPostProcessor接口方法。這些接口的實現類是獨立於bean的,而且會註冊到Spring容器中。在Spring容器建立任何Bean的時候,這些後處理器都會發生做用。
  4. 工廠後處理器方法(BeanFactoryProcessor一系列接口):包括AspectJWeavingEnabler、CustomAutowireConfigurer、ConfigurationClassPostProcessor等。這些都是Spring框架中已經實現好的BeanFactoryPostProcessor,用來實現某些特定的功能。

Bean自身的方法和Bean級生命週期方法都只對當前Bean起做用,可是容器級生命週期方法和工廠後處理器方法是對全部的bean都起做用post

對於這幾類方法,1 2 4都很好理解,下面咱們重點來講一下什麼是BeanPostProcessor和BeanFactoryPostProcessor

以我我的理解來講,BeanPostProcessor和BeanFactoryPostProcessor就是Spring建立的擴展點,用戶能夠建立本身的實現類來修改Bean或者BeanFactory

注意對於ApplicatonContext來講,容器能夠自動檢測並加載BeanPostProcessor和BeanFactoryPostProcessor,可是BeanFactory不行,須要本身調用方法手動註冊。BeanPostProcessor和BeanFactoryPostProcessor均可以有多個。
ApplicationContext也能夠根據org.springframework.core.PriorityOrdered和org.springframework.core.Ordered來進行自定義排序,可是BeanFactory不能夠,默認順序就是註冊順序

這裏我須要說明下面兩個容易混淆的單詞:

  • Instantiation:實例化,指的是調用構造函數進行實例化
  • Initialization:初始化,在Bean的聲明週期中指的是init-method所指定的方法或者是InitializingBean.afterPropertiesSet()方法

下面咱們對經常使用的這些接口進行說明:

經常使用接口說明

  1. BeanNameAware
    該接口只有一個方法setBeanName(String name),用來獲取bean的id或者name

  2. BeanFactoryAware
    該接口只有一個方法setBeanFactory(BeanFactory beanFactory),用來獲取當前環境中的BeanFactory

  3. ApplicationContextAware
    該接口只有一個方法setApplicationContext(ApplicationContext applicationContext),用來獲取當前環境中的ApplicationContext

    獲取到IOC容器以後,能夠對beans進行修改等操做

  4. InitializingBean
    該接口只有一個方法afterPropertiesSet(),在屬性注入完成後調用

  5. DisposableBean
    該接口只有一個方法destroy(),在容器銷燬的時候調用,在用戶指定的destroy-method以前調用

  6. BeanPostProcessor
    該接口有兩個方法:

  • postProcessBeforeInitialization(Object bean, String beanName):在初始化以前調用此方法
  • postProcessAfterInitialization(Object bean, String beanName):在初始化以後調用此方法

經過方法簽名咱們能夠知道,咱們能夠經過beanName來篩選出咱們須要進行個性化定製的bean

  1. InstantiationAwareBeanPostProcessor
    該類是BeanPostProcessor的子接口,經常使用的有以下三個方法
  • postProcessBeforeInstantiation(Class beanClass, String beanName):在bean實例化以前調用
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName):在bean實例化以後、設置屬性前調用
  • postProcessAfterInstantiation(Class beanClass, String beanName):在Bean實例化以後調用

測試Bean生命週期

下面咱們來編寫一個實例來驗證咱們上面所說的Bean生命週期

首先,咱們新建一個User,這個Bean實現了咱們的BeanNameAware、ApplicationContextAware、InitializingBean、DisposableBean接口

而後咱們實現咱們本身的BeanPostProcessor

實現本身的InstantiationAwareBeanPostProcessor

xml配置文件以下

<context:component-scan base-package="com.xiaohuan.springtest"/>

<bean id="user" class="com.xiaohuan.springtest.beanlifecycle.User" init-method="myInit" destroy-method="myDestroy">
    <!-- 構造函數注入 -->
    <constructor-arg index="0" type="int">
        <value>1</value>
    </constructor-arg>
    <constructor-arg index="1" type="java.lang.String">
        <value>xiaohuan</value>
    </constructor-arg>

    <!-- setter方法注入 -->
    <property name="id" value="2"/>
    <property name="name" value="dahuan"/>
</bean>
複製代碼

編寫咱們本身的測試類

最後運行項目

相關文章
相關標籤/搜索