歡迎大家關(guān)注我的微信公眾號(hào)【老周聊架構(gòu)】壤追,Java后端主流技術(shù)棧的原理、源碼分析供屉、架構(gòu)以及各種互聯(lián)網(wǎng)高并發(fā)行冰、高性能、高可用的解決方案伶丐。
一悼做、前言
今天我們來(lái)說(shuō)一說(shuō) Spring Bean 的生命周期,小伙伴們應(yīng)該在面試中經(jīng)常遇到哗魂,這是正掣刈撸現(xiàn)象。因?yàn)?Spring Bean 的生命周期是除了 IoC录别、AOP 幾個(gè)核心概念之外最重要概念朽色,大家務(wù)必拿下邻吞。可 Spring 源代碼又比較復(fù)雜葫男,跟著跟著就不知道跟到哪里去了抱冷,不太好拿下呀。這倒是真的梢褐,而且網(wǎng)上一上來(lái)就各種貼流程源碼旺遮,對(duì)初學(xué)者來(lái)說(shuō)是真的一臉懵逼,就像字都看的懂盈咳,但連在一塊就不知道意思了耿眉,太繞了。
本文老周試著講的通俗易懂些鱼响,讓更多的小伙伴們輕松的讀懂 Spring Bean 的生命周期鸣剪,并有對(duì)它有繼續(xù)研究學(xué)習(xí)的想法,那我寫(xiě)此文的目的也就達(dá)到了热押。
我們講 Spring Bean 的生命周期之前先來(lái)了解兩個(gè)概念:
1.1 什么是 Bean
我們來(lái)看下 Spring Framework 的官方文檔:
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 application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
簡(jiǎn)而言之西傀,bean 是由 Spring IoC 容器實(shí)例化、組裝和管理的對(duì)象桶癣。
1.2 什么是 Spring Bean 的生命周期
對(duì)于普通的 Java 對(duì)象,當(dāng) new 的時(shí)候創(chuàng)建對(duì)象娘锁,然后該對(duì)象就能夠使用了牙寞。一旦該對(duì)象不再被使用,則由 Java 自動(dòng)進(jìn)行垃圾回收莫秆。
而 Spring 中的對(duì)象是 bean间雀,bean 和普通的 Java 對(duì)象沒(méi)啥大的區(qū)別,只不過(guò) Spring 不再自己去 new 對(duì)象了镊屎,而是由 IoC 容器去幫助我們實(shí)例化對(duì)象并且管理它惹挟,我們需要哪個(gè)對(duì)象,去問(wèn) IoC 容器要即可缝驳。IoC 其實(shí)就是解決對(duì)象之間的耦合問(wèn)題连锯,Spring Bean 的生命周期完全由容器控制。
二用狱、Spring Bean 的生命周期
這里老周必須要提一下运怖,這里我們說(shuō)的 Spring Bean 的生命周期主要指的是 singleton bean,對(duì)于 prototype 的 bean 夏伊,Spring 在創(chuàng)建好交給使用者之后則不會(huì)再管理后續(xù)的生命周期摇展。
我們也來(lái)復(fù)習(xí)下 Spring 中的 bean 的作用域有哪些?
-
singleton
: 唯一 bean 實(shí)例,Spring 中的 bean 默認(rèn)都是單例的溺忧。 -
prototype
: 每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的 bean 實(shí)例咏连。 -
request
: 每一次 HTTP 請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的 bean盯孙,該 bean 僅在當(dāng)前 HTTP request 內(nèi)有效。 -
session
: 每一次 HTTP 請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的 bean祟滴,該 bean 僅在當(dāng)前 HTTP session 內(nèi)有效振惰。 -
global-session
: 全局 session 作用域,僅僅在基于 Portlet 的 web 應(yīng)用中才有意義踱启,Spring5 已經(jīng)沒(méi)有了报账。Portlet 是能夠生成語(yǔ)義代碼(例如:HTML)片段的小型 Java Web 插件。它們基于 portlet 容器埠偿,可以像 servlet 一樣處理 HTTP 請(qǐng)求透罢。但是,與 servlet 不同冠蒋,每個(gè) portlet 都有不同的會(huì)話(huà)羽圃。
我們知道對(duì)于普通的 Java 對(duì)象來(lái)說(shuō),它們的生命周期就是:
- 實(shí)例化
- 該對(duì)象不再被使用時(shí)通過(guò)垃圾回收機(jī)制進(jìn)行回收
而對(duì)于 Spring Bean 的生命周期來(lái)說(shuō):
- 實(shí)例化 Instantiation
- 屬性賦值 Populate
- 初始化 Initialization
- 銷(xiāo)毀 Destruction
實(shí)例化 -> 屬性賦值 -> 初始化 -> 銷(xiāo)毀
只有四個(gè)步驟抖剿,這樣拆解的話(huà)是不是感覺(jué)也不難朽寞?不像其他人寫(xiě)的那樣直接一上來(lái)就各種 BeanPostProcessor、BeanFactoryPostProcessor 全部懟進(jìn)流程里去斩郎,別說(shuō)讀者看著頭大脑融,自己寫(xiě)的可能短時(shí)間內(nèi)還記得流程,隔個(gè)一段時(shí)間缩宜,你可能都不知道自己寫(xiě)了個(gè)啥肘迎。
本來(lái)老周想通過(guò) Bean 創(chuàng)建流程入口
AbstractApplicationContext#refresh() 方法的 finishBeanFactoryInitialization(beanFactory) 處帶大家跟一下源碼,想了想還是不帶入過(guò)多的代碼進(jìn)來(lái)锻煌,直接給到最終的主要邏輯妓布。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 實(shí)例化階段 instanceWrapper = this.createBeanInstance(beanName, mbd, args); } ... Object exposedObject = bean; try { // 屬性賦值階段 this.populateBean(beanName, mbd, instanceWrapper); // 初始化階段 exposedObject = this.initializeBean(beanName, exposedObject, mbd); } catch (Throwable var18) { ... } ...}
至于銷(xiāo)毀,是在容器關(guān)閉時(shí)調(diào)用的宋梧,詳見(jiàn) ConfigurableApplicationContext#close()
是不是很清爽了匣沼?至于 BeanPostProcessor、BeanFactoryPostProcessor 以及其他的類(lèi)捂龄,在老周看來(lái)释涛,只不過(guò)是對(duì)主流程四個(gè)步驟的一系列擴(kuò)展點(diǎn)而已。
三跺讯、Spring Bean 的生命周期的擴(kuò)展點(diǎn)
Spring Bean 的生命周期的擴(kuò)展點(diǎn)超級(jí)多枢贿,老周這里不可能全部列出來(lái),只說(shuō)核心的擴(kuò)展點(diǎn)刀脏。這也就是為什么 Spring 的擴(kuò)展性很好的原因局荚,開(kāi)了很多的口子,盡可能讓某個(gè)功能高內(nèi)聚松耦合,用戶(hù)需要哪個(gè)功能就用哪個(gè)耀态,而不是直接來(lái)一個(gè)大而全的東西轮傍。
3.1 Bean 自身的方法
比如構(gòu)造函數(shù)茎匠、getter/setter 以及 init-method 和 destory-method 所指定的方法等镊掖,也就對(duì)應(yīng)著上文說(shuō)的實(shí)例化 -> 屬性賦值 -> 初始化 -> 銷(xiāo)毀四個(gè)階段粱哼。
3.2 容器級(jí)的方法(BeanPostProcessor 一系列接口)
主要是后處理器方法喳逛,比如下圖的 InstantiationAwareBeanPostProcessor
、BeanPostProcessor
接口方法竟宋。這些接口的實(shí)現(xiàn)類(lèi)是獨(dú)立于 Bean 的凳兵,并且會(huì)注冊(cè)到 Spring 容器中履腋。在 Spring 容器創(chuàng)建任何 Bean 的時(shí)候系奉,這些后處理器都會(huì)發(fā)生作用檬贰。
[圖片上傳失敗...(image-aa054e-1626625745817)]
3.2.1 InstantiationAwareBeanPostProcessor 源碼分析
我們翻一下源碼發(fā)現(xiàn) InstantiationAwareBeanPostProcessor 是繼承了 BeanPostProcessor
-
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
調(diào)用點(diǎn)
Object postProcessBeforeInstantiation(Class beanClass, String beanName)
返回值:如果返回的不為null,那么后續(xù)的Bean的創(chuàng)建流程【實(shí)例化缺亮、初始化afterProperties】都不會(huì)執(zhí)行翁涤,而是直接使用返回的快捷Bean,此時(shí)的正常執(zhí)行順序如下:
InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation萌踱,在實(shí)例化之前調(diào)用葵礼。
BeanPostProcessor接口中的postProcessAfterInitialization,在實(shí)例化之后調(diào)用并鸵。
總之鸳粉,postProcessBeforeInstantiation 在 doCreateBean 之前調(diào)用,也就是在 bean 實(shí)例化之前調(diào)用的园担,英文源碼注釋解釋道該方法的返回值會(huì)替換原本的 Bean 作為代理赁严,這也是 AOP 等功能實(shí)現(xiàn)的關(guān)鍵點(diǎn)。
-
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
調(diào)用點(diǎn)
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException
正常情況下在實(shí)例化之后在執(zhí)行populateBean之前調(diào)用
返回值:如果有指定的bean的時(shí)候返回false粉铐,那么后續(xù)的屬性填充和屬性依賴(lài)注入【populateBean】將不會(huì)執(zhí)行,同時(shí)后續(xù)的postProcessPropertyValues將不會(huì)執(zhí)行,但是初始化和BeanPostProcessor的仍然會(huì)執(zhí)行卤档。
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
實(shí)例化之后調(diào)用蝙泼,在方法applyPropertyValues【屬性填充】之前
返回值:如果返回null,那么將不會(huì)進(jìn)行后續(xù)的屬性填充劝枣,比如依賴(lài)注入等汤踏,如果返回的pvs額外的添加了屬性,那么后續(xù)會(huì)填充到該類(lèi)對(duì)應(yīng)的屬性中舔腾。
pvs:PropertyValues對(duì)象溪胶,用于封裝指定類(lèi)的對(duì)象,簡(jiǎn)單來(lái)說(shuō)就是PropertyValue的集合稳诚,里面相當(dāng)于以key-value形式存放類(lèi)的屬性和值哗脖。
pds:PropertyDescriptor對(duì)象數(shù)組,PropertyDescriptor相當(dāng)于存儲(chǔ)類(lèi)的屬性,不過(guò)可以調(diào)用set才避,get方法設(shè)置和獲取對(duì)應(yīng)屬性的值橱夭。
3.2.2 BeanPostProcessor 源碼分析
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
我們先來(lái)看
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
- 首先獲取到所有的后置處理器 getBeanPostProcessors()
- 在 for 循環(huán)中依次調(diào)用后置處理器的方法
processor.postProcessBeforeInitialization(result, beanName);
- 進(jìn)入 postProcessBeforeInitialization 方法
org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
進(jìn)入 invokeAwareInterfaces(bean);
方法,當(dāng)前 bean 實(shí)現(xiàn)了 ApplicationContextAware 接口桑逝。
-
ApplicationContextAwareProcessor#postProcessBeforeInitialization
首先判斷此 bean 是不是各種的Aware棘劣,如果是它列舉的那幾個(gè) Aware 就獲取 Bean 工廠的權(quán)限,可以向容器中導(dǎo)入相關(guān)的上下文環(huán)境楞遏,目的是為了 Bean 實(shí)例能夠獲取到相關(guān)的上下文茬暇,如果不是它列舉的幾個(gè) Aware,那就調(diào)用invokeAwareInterfaces(bean)
寡喝,向容器中添加相關(guān)接口的上下文環(huán)境糙俗。
3.3 工廠后處理器方法(BeanFactoryProcessor 一系列接口)
包括 AspectJWeavingEnabler
、CustomAutowireConfigurer
拘荡、ConfigurationClassPostProcessor
等臼节。這些都是 Spring 框架中已經(jīng)實(shí)現(xiàn)好的 BeanFactoryPostProcessor,用來(lái)實(shí)現(xiàn)某些特定的功能珊皿。
我們知道 Spring IoC 容器初始化的關(guān)鍵環(huán)節(jié)就在 org.springframework.context.support.AbstractApplicationContext#refresh
方法中 网缝,容器創(chuàng)建的主體流程都在這個(gè)方法里面,這個(gè)方法是真的重要sā7垭!
對(duì)于工廠后處理器方法老周這里直接帶你看 invokeBeanFactoryPostProcessors(beanFactory);
方法驶兜,這個(gè)方法處理的是 BeanFactoryPostProcessor
接口的 Bean扼仲。調(diào)用方法如下:
跟到最重要的方法里去,代碼雖長(zhǎng)抄淑,但邏輯中規(guī)中矩屠凶。
BeanFactoryPostProcessor
:一切處理 BeanFactory 的父接口
BeanDefinitionRegistryPostProcessor
:實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口的接口
流程說(shuō)明:
- 調(diào)用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(registry) 方法。參數(shù) beanFactoryPostProcessors 傳入的優(yōu)先處理掉肆资。然后獲取容器注冊(cè)的矗愧,對(duì)于這些 Bean 按照 PriorityOrdered 接口、Ordered郑原、沒(méi)有排序接口的實(shí)例分別進(jìn)行處理唉韭。
- 調(diào)用 BeanFactoryPostProcessor#postProcessBeanFactory(beanFactory) 方法。備注:BeanDefinitionRegistryPostProcessor 屬于 BeanFactoryPostProcessor 子接口犯犁。先處理屬于 BeanDefinitionRegistryPostProcessor 接口實(shí)例的 postProcessBeanFactory(beanFactory) 方法属愤,然后獲取容器注冊(cè)的。對(duì)于這些 Bean 按照 PriorityOrdered 接口酸役、Ordered住诸、沒(méi)有排序接口的實(shí)例分別進(jìn)行處理驾胆。
3.4 Bean 級(jí)生命周期方法
可以理解為 Bean 類(lèi)直接實(shí)現(xiàn)接口的方法,比如 BeanNameAware
只壳、BeanFactoryAware
俏拱、ApplicationContextAware
、InitializingBean
吼句、DisposableBean
等方法锅必,這些方法只對(duì)當(dāng)前 Bean 生效。
3.4.1 Aware 類(lèi)型的接口
Aware 類(lèi)型的接口的作用就是讓我們能夠拿到 Spring 容器中的一些資源惕艳「阋基本都能夠見(jiàn)名知意,Aware 之前的名字就是可以拿到什么資源远搪,例如 BeanNameAware 可以拿到 BeanName劣纲,以此類(lèi)推。調(diào)用時(shí)機(jī)需要注意:所有的 Aware 方法都是在初始化階段之前調(diào)用的
谁鳍。
Aware 接口眾多癞季,這里同樣通過(guò)分類(lèi)的方式幫助大家記憶。Aware 接口具體可以分為兩組倘潜,至于為什么這么分绷柒,詳見(jiàn)下面的源碼分析。如下排列順序同樣也是 Aware 接口的執(zhí)行順序涮因,能夠見(jiàn)名知意的接口不再解釋废睦。
Aware Group1
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Aware Group2
EnvironmentAware
-
EmbeddedValueResolverAware
這個(gè)知道的人可能不多,實(shí)現(xiàn)該接口能夠獲取 Spring EL 解析器养泡,用戶(hù)的自定義注解需要支持 SPEL 表達(dá)式的時(shí)候可以使用嗜湃,非常方便。 -
ApplicationContextAware(ResourceLoaderAware/ApplicationEventPublisherAware/MessageSourceAware)
這幾個(gè)接口可能讓人有點(diǎn)懵澜掩,實(shí)際上這幾個(gè)接口可以一起記购披,其返回值實(shí)質(zhì)上都是當(dāng)前的 ApplicationContext 對(duì)象,因?yàn)?ApplicationContext 是一個(gè)復(fù)合接口肩榕,如下:
Aware 調(diào)用時(shí)機(jī)源碼分析
可以看到并不是所有的 Aware 接口都使用同樣的方式調(diào)用今瀑。Bean××Aware 都是在代碼中直接調(diào)用的,而 ApplicationContext 相關(guān)的 Aware 都是通過(guò) BeanPostProcessor#postProcessBeforeInitialization() 實(shí)現(xiàn)的点把。感興趣的可以自己看一下 ApplicationContextAwareProcessor 這個(gè)類(lèi)的源碼,就是判斷當(dāng)前創(chuàng)建的 Bean 是否實(shí)現(xiàn)了相關(guān)的 Aware 方法屿附,如果實(shí)現(xiàn)了會(huì)調(diào)用回調(diào)方法將資源傳遞給 Bean郎逃。
BeanPostProcessor 的調(diào)用時(shí)機(jī)也能在這里體現(xiàn),包圍住 invokeInitMethods 方法挺份,也就說(shuō)明了在初始化階段的前后執(zhí)行褒翰。
關(guān)于 Aware 接口的執(zhí)行順序,其實(shí)只需要記住第一組在第二組執(zhí)行之前就行了。
3.4.2 生命周期接口
至于剩下的兩個(gè)生命周期接口就很簡(jiǎn)單了优训,實(shí)例化和屬性賦值都是 Spring 幫助我們做的朵你,能夠自己實(shí)現(xiàn)的有初始化和銷(xiāo)毀兩個(gè)生命周期階段。
-
InitializingBean
對(duì)應(yīng)生命周期的初始化階段揣非,在上面源碼的invokeInitMethods(beanName, wrappedBean, mbd);
方法中調(diào)用抡医。
有一點(diǎn)需要注意,因?yàn)?Aware 方法都是執(zhí)行在初始化方法之前早敬,所以可以在初始化方法中放心大膽的使用 Aware 接口獲取的資源忌傻,這也是我們自定義擴(kuò)展 Spring 的常用方式。
除了實(shí)現(xiàn) InitializingBean 接口之外還能通過(guò)注解或者 xml 配置的方式指定初始化方法搞监,至于這幾種定義方式的調(diào)用順序其實(shí)沒(méi)有必要記水孩。因?yàn)檫@幾個(gè)方法對(duì)應(yīng)的都是同一個(gè)生命周期,只是實(shí)現(xiàn)方式不同琐驴,我們一般只采用其中一種方式俘种。 -
DisposableBean
類(lèi)似于 InitializingBean,對(duì)應(yīng)生命周期的銷(xiāo)毀階段绝淡,以ConfigurableApplicationContext#close()
方法作為入口宙刘,實(shí)現(xiàn)是通過(guò)循環(huán)取所有實(shí)現(xiàn)了 DisposableBean 接口的 Bean 然后調(diào)用其 destroy() 方法,感興趣的可以自行跟一下源碼够委。
3.5 Spring Bean 生命周期流程圖
四荐类、常用接口說(shuō)明
4.1 BeanNameAware
該接口只有一個(gè)方法 setBeanName(String name)
,用來(lái)獲取 bean 的 id 或者 name
茁帽。
4.2 BeanFactoryAware
該接口只有一個(gè)方法 setBeanFactory(BeanFactory beanFactory)
玉罐,用來(lái)獲取當(dāng)前環(huán)境中的 BeanFactory
。
4.3 ApplicationContextAware
該接口只有一個(gè)方法 setApplicationContext(ApplicationContext applicationContext)
潘拨,用來(lái)獲取當(dāng)前環(huán)境中的 ApplicationContext
吊输。
4.4 InitializingBean
該接口只有一個(gè)方法 afterPropertiesSet()
,在屬性注入完成后調(diào)用
铁追。
4.5 DisposableBean
該接口只有一個(gè)方法 destroy()
季蚂,在容器銷(xiāo)毀的時(shí)候調(diào)用,在用戶(hù)指定的 destroy-method 之前調(diào)用
琅束。
4.6 BeanPostProcessor
該接口有兩個(gè)方法:
-
postProcessBeforeInitialization(Object bean, String beanName)
:在初始化之前
調(diào)用此方法 -
postProcessAfterInitialization(Object bean, String beanName)
:在初始化之后
調(diào)用此方法
通過(guò)方法簽名我們可以知道扭屁,我們可以通過(guò) beanName 來(lái)篩選出我們需要進(jìn)行個(gè)性化定制的 bean。
4.7 InstantiationAwareBeanPostProcessor
該類(lèi)是 BeanPostProcessor 的子接口涩禀,常用的有如下三個(gè)方法:
-
postProcessBeforeInstantiation(Class beanClass, String beanName)
:在bean實(shí)例化之前
調(diào)用 -
postProcessProperties(PropertyValues pvs, Object bean, String beanName)
:在bean實(shí)例化之后料滥、設(shè)置屬性前
調(diào)用 -
postProcessAfterInstantiation(Class beanClass, String beanName)
:在bean實(shí)例化之后
調(diào)用
五、代碼演示
思路:創(chuàng)建一個(gè)類(lèi) UserBean 艾船,讓其實(shí)現(xiàn)幾個(gè)特殊的接口葵腹,并分別在接口實(shí)現(xiàn)的構(gòu)造器高每、接口方法中斷點(diǎn),觀察線程調(diào)用棧践宴,分析出 Bean 對(duì)象創(chuàng)建和管理關(guān)鍵點(diǎn)的觸發(fā)時(shí)機(jī)鲸匿。
5.1 UserBean 類(lèi)
@Componentpublic class UserBean implements InitializingBean, BeanNameAware, DisposableBean, ApplicationContextAware { private int id; private String name; public UserBean(int id, String name) { this.id = id; this.name = name; System.out.println("2. 調(diào)用構(gòu)造函數(shù)"); } public int getId() { return id; } public void setId(int id) { this.id = id; System.out.println("5. 屬性注入 id"); } public String getName() { return name; } public void setName(String name) { this.name = name; System.out.println("5. 屬性注入 name"); } @Override public void setBeanName(String name) { System.out.println("6. 調(diào)用 BeanNameAware.setBeanName() 方法"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { UserBean userBean = (UserBean) applicationContext.getBean("userBean"); System.out.println(userBean); System.out.println("7. 調(diào)用 BeanNameAware.setBeanName() 方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("9. 調(diào)用 InitializingBean.afterPropertiesSet() 方法"); } public void myInit() { System.out.println("10. 調(diào)用 init-method 方法"); } @Override public void destroy() throws Exception { System.out.println("12. 調(diào)用 DisposableBean.destroy() 方法"); } public void myDestroy() { System.out.println("13. 調(diào)用 destroy-method 方法"); } @Override public String toString() { return "UserBean{" + "id=" + id + ", name='" + name + '\'' + '}'; }}
5.2 InstantiationAwareBeanPostProcessor 接口實(shí)現(xiàn)類(lèi)
@Componentpublic class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor { @Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if ("userBean".equals(beanName)) { System.out.println("1. 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法"); } return null; } @Override public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { if ("userBean".equals(beanName)) { UserBean userBean = (UserBean) bean; System.out.println("3. 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法"); System.out.println(userBean); } return true; } @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { if ("userBean".equals(beanName)) { System.out.println("4. 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法"); } return null; }}
5.3 BeanPostProcessor 接口實(shí)現(xiàn)類(lèi)
@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if ("userBean".equals(beanName)) { System.out.println("8. 調(diào)用 BeanPostProcessor.postProcessBeforeInitialization() 方法"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if ("userBean".equals(beanName)) { System.out.println("11. 調(diào)用 BeanPostProcessor.postProcessAfterInitialization() 方法"); } return bean; }}
5.4 BeanFactoryPostProcessor 接口實(shí)現(xiàn)類(lèi)
@Componentpublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("0. 調(diào)用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法"); }}
5.5 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.riemann.test.MyInstantiationAwareBeanPostProcessor" /> <bean id="userBean" class="com.riemann.test.UserBean" init-method="myInit" destroy-method="myDestroy"> <!-- 構(gòu)造函數(shù)注入 --> <constructor-arg index="0" type="int"> <value>1</value> </constructor-arg> <constructor-arg index="1" type="java.lang.String"> <value>微信公眾號(hào)【老周聊架構(gòu)】</value> </constructor-arg> <!-- setter方法注入 --> <property name="id" value="2"/> <property name="name" value="riemann"/> </bean> <bean class="com.riemann.test.MyBeanPostProcessor" /> <bean class="com.riemann.test.MyBeanFactoryPostProcessor" /></beans>
5.6 測(cè)試類(lèi)
public class BeanLifeCycleTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); UserBean user = (UserBean) applicationContext.getBean("userBean"); ((AbstractApplicationContext) applicationContext).close(); }}
5.7 控制臺(tái)結(jié)果打印