spring-bean生命周期

一篱蝇、Bean 的完整生命周期

1.1 Bean的核心構(gòu)造過程

在傳統(tǒng)的Java應(yīng)用中催式,bean的生命周期很簡(jiǎn)單,使用Java關(guān)鍵字 new 進(jìn)行Bean 的實(shí)例化呜舒,然后該Bean 就能夠使用了锭汛。一旦bean不再被使用,則由Java自動(dòng)進(jìn)行垃圾回收袭蝗。相比之下唤殴,Spring管理Bean的生命周期就復(fù)雜多了,正確理解Bean 的生命周期非常重要到腥,因?yàn)镾pring對(duì)Bean的管理可擴(kuò)展性非常強(qiáng)朵逝,下面展示了一個(gè)Bean的構(gòu)造過程:

image

如上圖所示,Bean 的生命周期還是比較復(fù)雜的乡范,下面來對(duì)上圖每一個(gè)步驟做文字描述:

Spring啟動(dòng)配名,查找并加載需要被Spring管理的bean,進(jìn)行Bean的實(shí)例化

Bean實(shí)例化后對(duì)將Bean的引入和值注入到Bean的屬性中


如果Bean實(shí)現(xiàn)了BeanNameAware接口的話晋辆,Spring將Bean的Id傳遞給setBeanName()方法

如果Bean實(shí)現(xiàn)了BeanFactoryAware接口的話渠脉,Spring將調(diào)用setBeanFactory()方法,將BeanFactory容器實(shí)例傳入

如果Bean實(shí)現(xiàn)了ApplicationContextAware接口的話瓶佳,Spring將調(diào)用Bean的setApplicationContext()方法连舍,將bean所在應(yīng)用上下文引用傳入進(jìn)來。


如果Bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring就將調(diào)用他們的postProcessBeforeInitialization()方法索赏。

如果Bean 實(shí)現(xiàn)了InitializingBean接口盼玄,Spring將調(diào)用他們的afterPropertiesSet()方法。類似的潜腻,如果bean使用init-method聲明了初始化方法埃儿,該方法也會(huì)被調(diào)用

如果Bean 實(shí)現(xiàn)了BeanPostProcessor接口,Spring就將調(diào)用他們的postProcessAfterInitialization()方法融涣。

此時(shí)童番,Bean已經(jīng)準(zhǔn)備就緒,可以被應(yīng)用程序使用了威鹿。他們將一直駐留在應(yīng)用上下文中剃斧,直到應(yīng)用上下文被銷毀。

如果bean實(shí)現(xiàn)了DisposableBean接口忽你,Spring將調(diào)用它的destroy()接口方法幼东,同樣,如果bean使用了destory-method 聲明銷毀方法科雳,該方法也會(huì)被調(diào)用根蟹。

1.2 Bean的全部構(gòu)造過程(超詳細(xì))

   1.1節(jié)介紹了Spring 中Bean的核心接口和生命周期,還有另外的初始化過程涉及的接口糟秘,摘自org.springframework.beans.factory.BeanFactory简逮, 全部相關(guān)接口如下:

Bean的初始化:

image

BeanNameAware.setBeanName() 在創(chuàng)建此bean的bean工廠中設(shè)置bean的名稱,在普通屬性設(shè)置之后調(diào)用尿赚,在InitializinngBean.afterPropertiesSet()方法之前調(diào)用.

** BeanClassLoaderAware.setBeanClassLoader(): 在普通屬性設(shè)置之后散庶,InitializingBean.afterPropertiesSet()之前調(diào)用**

** BeanFactoryAware.setBeanFactory() : 回調(diào)提供了自己的bean實(shí)例工廠,在普通屬性設(shè)置之后凌净,在InitializingBean.afterPropertiesSet()或者自定義初始化方法之前調(diào)用**

** EnvironmentAware.setEnvironment(): 設(shè)置environment在組件使用時(shí)調(diào)用**

** EmbeddedValueResolverAware.setEmbeddedValueResolver(): 設(shè)置StringValueResolver 用來解決嵌入式的值域問題**

** ResourceLoaderAware.setResourceLoader(): 在普通bean對(duì)象之后調(diào)用悲龟,在afterPropertiesSet 或者自定義的init-method 之前調(diào)用,在 ApplicationContextAware 之前調(diào)用泻蚊。**

** ApplicationEventPublisherAware.setApplicationEventPublisher(): 在普通bean屬性之后調(diào)用,在初始化調(diào)用afterPropertiesSet 或者自定義初始化方法之前調(diào)用丑婿。在 ApplicationContextAware 之前調(diào)用性雄。**

** MessageSourceAware.setMessageSource(): 在普通bean屬性之后調(diào)用,在初始化調(diào)用afterPropertiesSet 或者自定義初始化方法之前調(diào)用羹奉,在 ApplicationContextAware 之前調(diào)用秒旋。**

** ApplicationContextAware.setApplicationContext(): 在普通Bean對(duì)象生成之后調(diào)用,在InitializingBean.afterPropertiesSet之前調(diào)用或者用戶自定義初始化方法之前诀拭。在ResourceLoaderAware.setResourceLoader迁筛,ApplicationEventPublisherAware.setApplicationEventPublisher,MessageSourceAware之后調(diào)用耕挨。**

** ServletContextAware.setServletContext(): 運(yùn)行時(shí)設(shè)置ServletContext细卧,在普通bean初始化后調(diào)用尉桩,在InitializingBean.afterPropertiesSet之前調(diào)用,在 ApplicationContextAware 之后調(diào)用注:是在WebApplicationContext 運(yùn)行時(shí)**

** BeanPostProcessor.postProcessBeforeInitialization() : 將此BeanPostProcessor 應(yīng)用于給定的新bean實(shí)例 在任何bean初始化回調(diào)方法(像是InitializingBean.afterPropertiesSet或者自定義的初始化方法)之前調(diào)用贪庙。這個(gè)bean將要準(zhǔn)備填充屬性的值蜘犁。返回的bean示例可能被普通對(duì)象包裝,默認(rèn)實(shí)現(xiàn)返回是一個(gè)bean止邮。**

** BeanPostProcessor.postProcessAfterInitialization() : 將此BeanPostProcessor 應(yīng)用于給定的新bean實(shí)例 在任何bean初始化回調(diào)方法(像是InitializingBean.afterPropertiesSet或者自定義的初始化方法)之后調(diào)用这橙。這個(gè)bean將要準(zhǔn)備填充屬性的值。返回的bean示例可能被普通對(duì)象包裝**

** InitializingBean.afterPropertiesSet(): 被BeanFactory在設(shè)置所有bean屬性之后調(diào)用(并且滿足BeanFactory 和 ApplicationContextAware)导披。**

Bean的銷毀:

在BeanFactory 關(guān)閉的時(shí)候屈扎,Bean的生命周期會(huì)調(diào)用如下方法:

** DestructionAwareBeanPostProcessor.postProcessBeforeDestruction(): 在銷毀之前將此BeanPostProcessor 應(yīng)用于給定的bean實(shí)例。能夠調(diào)用自定義回調(diào)撩匕,像是DisposableBean 的銷毀和自定義銷毀方法鹰晨,這個(gè)回調(diào)僅僅適用于工廠中的單例bean(包括內(nèi)部bean)。**

        實(shí)現(xiàn)了自定義的destory()方法

二滑沧、Bean 的生命周期驗(yàn)證

2.1 驗(yàn)證Bean生命周期的過程

public class Book implements BeanNameAware,BeanFactoryAware,

** ApplicationContextAware,InitializingBean,DisposableBean {**

** private String bookName;**

** public Book(){**

** System.out.println("Book Initializing ");**

** }**

** public void setBeanFactory(BeanFactory beanFactory) throws BeansException {**

** System.out.println("Book.setBeanFactory invoke");**

** }**

** public void setBeanName(String name) {**

** System.out.println("Book.setBeanName invoke");**

** }**

** public void destroy() throws Exception {**

** System.out.println("Book.destory invoke");**

** }**

** public void afterPropertiesSet() throws Exception {**

** System.out.println("Book.afterPropertiesSet invoke");**

** }**

** public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {**

** System.out.println("Book.setApplicationContext invoke");**

** }**

** public String getBookName() {**

** return bookName;**

** }**

** public void setBookName(String bookName) {**

** this.bookName = bookName;**

** System.out.println("setBookName: Book name has set.");**

** }**

** public void myPostConstruct(){**

** System.out.println("Book.myPostConstruct invoke");**

** }**

** // 自定義初始化方法**

** @PostConstruct**

** public void springPostConstruct(){**

** System.out.println("@PostConstruct");**

** }**

** public void myPreDestory(){**

** System.out.println("Book.myPreDestory invoke");**

** System.out.println("---------------destroy-----------------");**

** }**

** // 自定義銷毀方法**

** @PreDestroy**

** public void springPreDestory(){**

** System.out.println("@PreDestory");**

** }**

** @Override**

** protected void finalize() throws Throwable {**

** System.out.println("------inside finalize-----");**

** }**

}

public class MyBeanPostProcessor implements BeanPostProcessor {

// 容器加載的時(shí)候會(huì)加載一些其他的bean并村,會(huì)調(diào)用初始化前和初始化后方法

// 這次只關(guān)注book(bean)的生命周期

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

    if(bean instanceof Book){

        System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");

    }

    return bean;

}

public Object postProcessAfterInitialization(Object bean, String beanName) throws  

 BeansException {

    if(bean instanceof Book){

        System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");

    }

    return bean;

}

}

<beans xmlns="http://www.springframework.org/schema/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-2.5.xsd     http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd">

  <!-- 掃描bean -->

<context:component-scan base-package="com.bean.lifecycle"/>

<!-- 實(shí)現(xiàn)了用戶自定義初始化和銷毀方法 -->

<bean id="book" class="com.bean.lifecycle.Book" init-method="myPostConstruct" destroy-method="myPreDestory">

      <!-- 注入bean 屬性名稱 -->

    <property name="bookName" value="thingking in java" />

</bean>

  <!--引入自定義的BeanPostProcessor-->

<bean class="com.bean.lifecycle.MyBeanPostProcessor"/>

</beans>

測(cè)試結(jié)果如下:

Book Initializing

setBookName: Book name has set.

Book.setBeanName invoke

Book.setBeanFactory invoke

Book.setApplicationContext invoke

MyBeanPostProcessor.postProcessBeforeInitialization

@PostConstruct

Book.afterPropertiesSet invoke

Book.myPostConstruct invoke

MyBeanPostProcessor.postProcessAfterInitialization

Book name = thingking in java

@PreDestory

Book.destory invoke

Book.myPreDestory invoke

---------------destroy————————

完整的測(cè)試結(jié)果:

Book Initializing

setBookName: Book name has set.

Book.setBeanName invoke

Book.setBeanFactory invoke

Book.setApplicationContext invoke

MyBeanPostProcessor.postProcessBeforeInitialization

@PostConstruct

Book.afterPropertiesSet invoke

Book.myPostConstruct invoke

MyBeanPostProcessor.postProcessAfterInitialization

Book name = thingking in java

@PreDestory

Book.destory invoke

Book.myPreDestory invoke

---------------destroy-----------------

Book Initializing

設(shè)置BookSystem 的屬性值

Book.setBeanName invoke

SubBookClass.setBeanClassLoader() 方法被調(diào)用了

Book.setBeanFactory invoke

SubBookClass.setEnvironment() 方法被調(diào)用了

SubBookClass.setEmbeddedValueResolver() 方法被調(diào)用了

SubBookClass.setResourceLoader() 方法被調(diào)用了

SubBookClass.setApplicationEventPublisher() 方法被調(diào)用了

SubBookClass.setMessageSource() 方法被調(diào)用了

Book.setApplicationContext invoke

MyBeanPostProcessor.postProcessBeforeInitialization

Book.afterPropertiesSet invoke

Book.myPostConstruct invoke

MyBeanPostProcessor.postProcessAfterInitialization

BookSystemName = Java System

Book.destory invoke

Book.myPreDestory invoke

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市滓技,隨后出現(xiàn)的幾起案子哩牍,更是在濱河造成了極大的恐慌,老刑警劉巖令漂,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膝昆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡叠必,警方通過查閱死者的電腦和手機(jī)荚孵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纬朝,“玉大人收叶,你說我怎么就攤上這事」部粒” “怎么了判没?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)隅茎。 經(jīng)常有香客問我澄峰,道長(zhǎng),這世上最難降的妖魔是什么辟犀? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任俏竞,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘魂毁。我一直安慰自己玻佩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布漱牵。 她就那樣靜靜地躺著夺蛇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酣胀。 梳的紋絲不亂的頭發(fā)上刁赦,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音闻镶,去河邊找鬼甚脉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛铆农,可吹牛的內(nèi)容都是我干的牺氨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼墩剖,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼猴凹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起岭皂,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤郊霎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后爷绘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體书劝,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年土至,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了购对。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陶因,死狀恐怖骡苞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情楷扬,我是刑警寧澤解幽,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站毅否,受9級(jí)特大地震影響亚铁,放射性物質(zhì)發(fā)生泄漏蝇刀。R本人自食惡果不足惜螟加,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捆探,春花似錦然爆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至助被,卻和暖如春剖张,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揩环。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工搔弄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丰滑。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓顾犹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親褒墨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子炫刷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容