第7章-Spring的Bean生命周期和擴展點

Spring 的核心是 IoC 容器悴能,了解 Bean 的生命周期非常重要蛇券,這對 Spring 在項目中的應(yīng)用和擴展都很有幫助崖疤。

一仰冠、生命周期

Bean 的生命周期主要為實例化、屬性填充轻腺、初始化和銷毀 4 個階段乐疆,加上類加載和使用階段,整個流程如下:

二贬养、Bean 的擴展

Spring 在每個階段都提供了擴展點挤土,擴展點可以分為兩類:

  • 專用擴展點:用于單個 Bean 的擴展,定義 Bean 類時實現(xiàn)接口來擴展功能误算。
  • 通用擴展點:用于所有 Bean 的擴展仰美,單獨定義類實現(xiàn)接口來擴展功能。

1. 專用擴展點

Aware 接口

Aware 接口可以在屬性填充的時候注入 Bean 信息或上下文等信息儿礼。
例如可以通過實現(xiàn) BeanNameAware 接口將當(dāng)前 Bean 的名稱注入到類中咖杂。

public class OneBeanExample implements BeanNameAware {

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

Spring 提供了許多 Aware 的子接口可以使用,常用的有:

Aware接口 注入依賴
BeanNameAware Bean 的名稱
BeanFactoryAware 當(dāng)前上下文的 BeanFactory
ApplicationContextAware 當(dāng)前上下文的 ApplicationContext
ApplicationEventPublisherAware 當(dāng)前上下文的事件發(fā)布者 ApplicationEventPublisher
BeanClassLoaderAware 加載 Bean 類的類加載器

InitializingBeanDisposableBean 接口

如果要在 Bean 初始化時添加自定義邏輯蜘犁,可以實現(xiàn) InitializingBean 接口翰苫。
如果要在 Bean 銷毀時添加自定義邏輯,可以實現(xiàn) DisposableBean 接口这橙。

public class OneBeanExample implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() {
        // do some initialization work
    }

    @Override
    public void destroy() {
        // do some destruction work
    }
}

除了上面兩個回調(diào)接口奏窑,也可以在注冊 Bean 的時候指定自定義初始化和銷毀方法。
@Bean 注解的 initMethod 屬性指定 Bean 初始化方法屈扎,destroyMethod 屬性指定 Bean 銷毀方法埃唯。

public class OneBeanExample {

    public void init() {
        // do some initialization work
    }

    public void destroy() {
        // do some destruction work
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public OneBeanExample oneBeanExample() {
        return new OneBeanExample();
    }
}

對應(yīng) XML 配置 <bean> 標簽的 init-methoddestroy-method 屬性。
還可以使用 JDK 的 @PostConstruct@PreDestroy 注解來指定初始化方法和銷毀方法鹰晨。

public class OneBeanExample {

    @PostConstruct
    public void init() {
        // do some initialization work
    }

    @PreDestroy
    public void destroy() {
        // do some destruction work
    }
}

前面提供的三種方式都可以定義 Bean 初始化和銷毀時執(zhí)行的方法墨叛。

InitializingBeanDisposableBean 接口會和 Spring 強耦合。
當(dāng)項目中沒有依賴 Spring 時模蜡,推薦使用第二種或第三種方式漠趁。

2. 通用擴展點

通用擴展點對所有 Bean 有效,需要定義單獨的類來實現(xiàn)忍疾,主要有三個接口:

  • BeanPostProcessor 接口
  • InstantiationAwareBeanPostProcessor 接口
  • DestructionAwareBeanPostProcessor 接口

BeanPostProcessor 接口

實現(xiàn)該接口可以在 Bean 初始化前后添加自定義邏輯闯传。

@Component
public class BeanInitProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // before initialization work
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // after initialization work
        return bean;
    }
}

InstantiationAwareBeanPostProcessor 接口

實現(xiàn)該接口可以在 Bean 實例化前后添加自定義邏輯。

@Component
public class BeanInstanceProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        // before instantiation work
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        // after instantiation work
        return true;
    }
}

DestructionAwareBeanPostProcessor 接口

實現(xiàn)該接口可以在 Bean 銷毀前添加自定義邏輯卤妒。

@Component
public class BeanDestroyProcessor implements DestructionAwareBeanPostProcessor {

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        // before destruction work
    }
}

3. 生命周期擴展點示例

Bean 生命周期的 4 個階段都支持擴展甥绿,每個階段都可以添加自定義邏輯。

3.1 實例化

Spring 容器在這步實例化 Bean 對象则披。
實現(xiàn) InstantiationAwareBeanPostProcessor 接口的兩個擴展方法共缕,在實例化前后添加擴展。

3.2 屬性填充

Spring 容器在這步填充屬性士复,例如通過 Setter 方法注入依賴图谷。
屬性填充后通過 Aware 接口擴展來注入 Bean 信息或上下文等信息。

3.2 初始化

Spring 容器在這步初始化 Bean。
實現(xiàn) BeanPostProcessor 接口的兩個擴展方法蜓萄,在初始化前后添加擴展隅茎。

在初始化階段,前面講到三種方式來指定初始化方法嫉沽,一般情況下使用一種就行。
如果同時使用三種俏竞,三種方式指定的方法相同绸硕,該方法只執(zhí)行一次,當(dāng)三種方式指定的方法不同魂毁,按圖中順序執(zhí)行玻佩。

3.4 銷毀

Spring 容器在這步銷毀 Bean,可以釋放外部資源席楚。
實現(xiàn) DestructionAwareBeanPostProcessor 接口的擴展方法咬崔,可以在銷毀前添加擴展。

在銷毀階段烦秩,前面講到三種方式來指定銷毀方法垮斯,一般情況下使用一種就行。
如果同時使用三種只祠,三種方式指定的方法相同兜蠕,該方法只執(zhí)行一次,當(dāng)三種方式指定的方法不同抛寝,按圖中順序執(zhí)行熊杨。

4. 生命周期擴展點順序

Bean 的生命周期中,通用擴展點和專用擴展點盗舰,以及它們對應(yīng)的方法晶府,執(zhí)行順序如下圖:

三、附錄

1. 配置屬性

屬性 描述
<bean>init-method屬性 基于 XML 配置容器中钻趋,指定自定義初始化方法
<bean>destroy-method屬性 基于 XML 配置容器中川陆,指定自定義銷毀方法

2. 常用注解

注解 描述
@BeaninitMethod屬性 基于 Java 配置容器中,指定自定義初始化方法
@BeandestroyMethod屬性 基于 Java 配置容器中爷绘,指定自定義銷毀方法
@PostConstruct 使用 JDK 注解指定初始化執(zhí)行的方法
@PreDestroy 使用 JDK 注解指定銷毀執(zhí)行的方法

3. 示例代碼

Gitee 倉庫:https://gitee.com/code_artist/spring
項目模塊:spring-ioc
示例路徑:cn.codeartist.spring.bean.life

最新文章關(guān)注 CodeArtist 碼匠公眾號书劝。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市土至,隨后出現(xiàn)的幾起案子购对,更是在濱河造成了極大的恐慌,老刑警劉巖陶因,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骡苞,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機解幽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門贴见,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躲株,你說我怎么就攤上這事片部。” “怎么了霜定?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵档悠,是天一觀的道長。 經(jīng)常有香客問我望浩,道長辖所,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任磨德,我火速辦了婚禮缘回,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘典挑。我一直安慰自己酥宴,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布搔弄。 她就那樣靜靜地躺著幅虑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪顾犹。 梳的紋絲不亂的頭發(fā)上倒庵,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音炫刷,去河邊找鬼擎宝。 笑死,一個胖子當(dāng)著我的面吹牛浑玛,可吹牛的內(nèi)容都是我干的绍申。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼顾彰,長吁一口氣:“原來是場噩夢啊……” “哼极阅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起涨享,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤筋搏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后厕隧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奔脐,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡俄周,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了髓迎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峦朗。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖排龄,靈堂內(nèi)的尸體忽然破棺而出波势,到底是詐尸還是另有隱情,我是刑警寧澤涣雕,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布艰亮,位于F島的核電站,受9級特大地震影響挣郭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疗韵,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一兑障、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蕉汪,春花似錦流译、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至驹马,卻和暖如春革砸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糯累。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工算利, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泳姐。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓效拭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胖秒。 傳聞我的和親對象是個殘疾皇子缎患,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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