新聞中心
在對(duì)于Spring的所有解讀中,Bean的生命周期都可謂是重中之重,甚至還有人稱(chēng)Spring就是個(gè)管理Bean的容器。Bean的生命周期之所以這么重要,被反復(fù)提及,是因?yàn)镾pring的核心能力,比如對(duì)象創(chuàng)建(IOC)、屬性注入(DI)、初始化方法的調(diào)用、代理對(duì)象的生成(AOP)等功能的實(shí)現(xiàn),都是在bean的生命周期中完成的。清楚了bean的生命周期,我們才能知道Spring的神奇魔法究竟是什么,是怎么一步步賦能,讓原本普通的java對(duì)象,最終變成擁有超能力的bean的。

我們提供的服務(wù)有:網(wǎng)站制作、網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、萊蕪ssl等。為成百上千企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢(xún)和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的萊蕪網(wǎng)站制作公司
1. bean的生命周期
Spring的生命周期大致分為:創(chuàng)建 -> 屬性填充 -> 初始化bean -> 使用 -> 銷(xiāo)毀 幾個(gè)核心階段。我們先來(lái)簡(jiǎn)單了解一下這些階段所做的事情:
創(chuàng)建階段主要是創(chuàng)建對(duì)象,這里我們看到,對(duì)象的創(chuàng)建權(quán)交由Spring管理了,不再是我們手動(dòng)new了,這也是IOC的概念。
屬性填充階段主要是進(jìn)行依賴(lài)的注入,將當(dāng)前對(duì)象依賴(lài)的bean對(duì)象,從Spring容器中找出來(lái),然后填充到對(duì)應(yīng)的屬性中去。
初始化bean階段做的事情相對(duì)比較復(fù)雜,包括回調(diào)各種Aware接口、回調(diào)各種初始化方法、生成AOP代理對(duì)象也在該階段進(jìn)行,該階段主要是完成bean的初始化工作,后面我們慢慢分析。
使用bean階段,主要是bean創(chuàng)建完成,在程序運(yùn)行期間,提供服務(wù)的階段。
銷(xiāo)毀bean階段,主要是容器關(guān)閉或停止服務(wù),對(duì)bean進(jìn)行銷(xiāo)毀處理。
當(dāng)然,bean的生命周期中還包括其他的流程,比如合并beanDefinition、暴露工廠對(duì)象等,只是相對(duì)而言都是為其他功能做伏筆和準(zhǔn)備的,在講到對(duì)應(yīng)功能時(shí),我們?cè)谧鲈敿?xì)分析。
1.1 創(chuàng)建bean
對(duì)象的創(chuàng)建是bean生命周期的第一步,畢竟要先有1才能有0嘛。創(chuàng)建對(duì)象的方式有很多,比如 new、反射、clone等等,Spring是怎么創(chuàng)建對(duì)象的呢?絕大多數(shù)情況下,Spring是通過(guò)反射來(lái)創(chuàng)建對(duì)象的,不過(guò)如果我們提供了Supplier或者工廠方法,Spring也會(huì)直接使用我們提供的創(chuàng)建方式。
我們秉持一貫的風(fēng)格,從源碼出發(fā),看一下Spring是如何選擇創(chuàng)建方式的:
// 源碼位于 AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 再次解析BeanDefinition的class,確保class已經(jīng)被解析
Class> beanClass = resolveBeanClass(mbd, beanName);
// 1: 如果提供了Supplier,通過(guò)Supplier產(chǎn)生對(duì)象
Supplier> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 2: 如果有工廠方法,使用工廠方法產(chǎn)生對(duì)象
// 在@Configration配置@Bean的方法,也會(huì)被解析為FactoryMethod
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//...省略部分代碼
// 3: 推斷構(gòu)造方法
// 3.1 執(zhí)行后置處理器,獲取候選構(gòu)造方法
Constructor>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 3.2 需要自動(dòng)注入的情況
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 3.3 默認(rèn)使用沒(méi)有參數(shù)的構(gòu)造方法
return instantiateBean(beanName, mbd);
}
經(jīng)過(guò)我們跟蹤源碼,發(fā)現(xiàn)Spring推斷創(chuàng)建方式還是比較聰明的,具體邏輯是:
- 先判斷是否提供了Supplier,如果提供,則通過(guò)Supplier產(chǎn)生對(duì)象。
- 再判斷是否提供工廠方法,如果提供,則使用工廠方法產(chǎn)生對(duì)象。
- 如果都沒(méi)提供,需要進(jìn)行構(gòu)造方法的推斷,具體邏輯為:
如果僅有一個(gè)構(gòu)造方法,會(huì)直接使用該構(gòu)造方法(如果構(gòu)造方法有參數(shù),會(huì)自動(dòng)注入依賴(lài)參數(shù))
如果有多個(gè)構(gòu)造方法,會(huì)判斷有沒(méi)有加了@Autowired注解的構(gòu)造方法:
如果沒(méi)有,Spring默認(rèn)選擇無(wú)參構(gòu)造方法;
如果有,且有@Autowired(required=true)的構(gòu)造方法,就會(huì)選擇該構(gòu)造方法;
如果有,但是沒(méi)有@Autowired(required=true)的構(gòu)造方法,Spring會(huì)從所有加了@Autowired的構(gòu)造方法中,根據(jù)構(gòu)造器參數(shù)個(gè)數(shù)、類(lèi)型匹配程度等綜合打分,選擇一個(gè)匹配參數(shù)最多,類(lèi)型最準(zhǔn)確的構(gòu)造方法。
關(guān)于創(chuàng)建bean時(shí),具體如何選擇構(gòu)造方法的,本文我們不詳細(xì)展開(kāi)。因?yàn)楸疚闹髦荚谟诜治鯾ean的生命周期,我們只需要簡(jiǎn)單理解為:Spring會(huì)選擇一個(gè)構(gòu)造方法,然后通過(guò)反射創(chuàng)建出對(duì)象即可。其實(shí)在閱讀Spring源碼的時(shí)候,小伙伴們也一定要學(xué)會(huì)抓大放小,重點(diǎn)關(guān)注核心流程,細(xì)枝末節(jié)的地方可以先戰(zhàn)術(shù)性忽略,后續(xù)有需要時(shí)再回過(guò)頭分析也不遲,千萬(wàn)不要陷進(jìn)去,迷失了方向。
這里給感興趣的小伙伴附上一張流程圖,感興趣的小伙伴也可以留言,后續(xù)我們也可以單獨(dú)分析。
1.2 merged BeanDefinition
本階段是Spring提供的一個(gè)拓展點(diǎn),通過(guò)MergedBeanDefinitionPostProcessor類(lèi)型的后置處理器,可以對(duì)bean對(duì)應(yīng)的BeanDefinition進(jìn)行修改。Spring自身也充分利用該拓展點(diǎn),做了很多初始化操作(并沒(méi)有修改BeanDefinition),比如查找標(biāo)注了@Autowired、 @Resource、@PostConstruct、@PreDestory 的屬性和方法,方便后續(xù)進(jìn)行屬性注入和初始化回調(diào)。當(dāng)然,我們也可以自定義實(shí)現(xiàn),用來(lái)修改BeanDefinition信息或者我們需要的初始化操作,感興趣的小伙伴可以自行試一下哦。
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class> beanType, String beanName){
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}1.3 暴露工廠對(duì)象
本階段主要是將早期bean對(duì)象提前放入到三級(jí)緩存singletonFactories中,為循環(huán)依賴(lài)做支持。在后續(xù)進(jìn)行屬性填充時(shí),如果發(fā)生循環(huán)依賴(lài),可以從三級(jí)緩存中通過(guò)getObject()獲取該bean,完成循環(huán)依賴(lài)場(chǎng)景下的依賴(lài)注入。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 做循環(huán)依賴(lài)的支持 將早期實(shí)例化bean的ObjectFactory,添加到單例工廠(三級(jí)緩存)中
addSingletonFactory(beanName, () getEarlyBeanReference(beanName, mbd, bean));
}
該階段完全是為了支撐循環(huán)依賴(lài)的,是Spring為解決循環(huán)依賴(lài)埋的伏筆,在Bean的生命周期中完全可以忽略。這里為了完整性,和小伙伴們簡(jiǎn)單提及一下。
如果對(duì)Spring如何解決循環(huán)依賴(lài)不是很清楚的話(huà),可以看筆者的另一篇文章 聊透Spring循環(huán)依賴(lài),詳細(xì)分析了Spring循環(huán)依賴(lài)的解決之道,對(duì)本階段的內(nèi)容也有詳細(xì)的敘述。
1.4 屬性填充
本階段完成了Spring的核心功能之一:依賴(lài)注入,包括自動(dòng)注入、@Autowired注入、@Resource注入等。Spring會(huì)根據(jù)bean的注入模型(默認(rèn)不自動(dòng)注入),選擇根據(jù)名稱(chēng)自動(dòng)注入還是根據(jù)類(lèi)型自動(dòng)注入。然后調(diào)用InstantiationAwareBeanPostProcessor#postProcessProperties()完成@Autowired和@Resource的屬性注入。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw){
// 省略部分代碼
// 獲取bean的注入類(lèi)型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 1: 自動(dòng)注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 根據(jù)名稱(chēng)注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 根據(jù)類(lèi)型注入
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 2: 調(diào)用BeanPostProcessor,完成@Autowired @Resource屬性填充
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 重點(diǎn): 完成@Autowired @Resource屬性填充
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
// 需要注入的屬性,會(huì)過(guò)濾掉Aware接口包含的屬性(通過(guò)ignoreDependencyInterface添加)
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 3: 依賴(lài)檢查
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 4: 將屬性應(yīng)用到bean中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}關(guān)于依賴(lài)注入,筆者在 聊透Spring依賴(lài)注入 中有詳細(xì)分析,不清楚的小伙伴可以先去感受一下Spring依賴(lài)注入的奇妙之處。
1.5 初始化bean
該階段主要做bean的初始化操作,包括:回調(diào)Aware接口、回調(diào)初始化方法、生成代理對(duì)象等。
- invokeAwareMethods():回調(diào)BeanNameAware、BeanClassLoaderAware、BeanFactoryAware感知接口。
- 回調(diào)后置處理器的前置方法,其中:
ApplicationContextAwareProcessor: 回調(diào)EnvironmentAware、ResourceLoaderAware、ApplicationContextAware、ApplicationEventPublisherAware、MessageSourceAware、EmbeddedValueResolverAware感知接口。
InitDestroyAnnotationBeanPostProcessor:回調(diào)標(biāo)注了@PostConstruct的方法。
- invokeInitMethods()調(diào)用初始化方法:
如果bean是InitializingBean的子類(lèi), 先調(diào)用afterPropertiesSet()。
- 回調(diào)自定義的initMethod,比如通過(guò)@Bean(initMethod = "xxx")指定的初始化方法。
回調(diào)后置處理器的后置方法,可能返回代理對(duì)象。其中AbstractAutoProxyCreator和 AbstractAdvisingBeanPostProcessor都有可能產(chǎn)生代理對(duì)象,比如InfrastructureAdvisorAutoProxyCreator完成了@Transactional代理對(duì)象的生成,AsyncAnnotationBeanPostProcessor完成了@Async代理對(duì)象的生成。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 1: 回調(diào)Aware接口中的方法
// 完成Aware方法的回調(diào)(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware)
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 2: 調(diào)用before...方法
// ApplicationContextAwareProcessor: 其他Aware方法的回調(diào)
// InitDestroyAnnotationBeanPostProcessor: @PostConstruct方法的回調(diào)
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 3: 完成xml版本和@bean(initMethod)的init方法回調(diào)
invokeInitMethods(beanName, wrappedBean, mbd);
}
// 4: 調(diào)用after方法
// 重點(diǎn): AOP生成代理對(duì)象
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}在初始化完成后,bean會(huì)被放到單例池中,正式開(kāi)始自己的使命:為項(xiàng)目服務(wù),比如接收http請(qǐng)求,進(jìn)行CRUD等等。后續(xù)有使用到該bean的地方,也是直接從單例池中獲取,不會(huì)再次創(chuàng)建bean(僅單例的哦)。
2. bean的來(lái)龍去脈
2.1 bean的掃描階段
現(xiàn)在我們已經(jīng)知道Spring bean是如何創(chuàng)建的了,那什么時(shí)候創(chuàng)建這些bean呢,是遵循懶加載的思想,在實(shí)際使用的時(shí)候再創(chuàng)建嗎?其實(shí)不是的,因?yàn)閎ean之間的復(fù)雜關(guān)系和生命周期的原因,Spring在容器啟動(dòng)的時(shí)候,就會(huì)實(shí)例化這些bean,然后放到單例池中,后續(xù)即用即取。并且在創(chuàng)建前、創(chuàng)建中、創(chuàng)建后都會(huì)做很多檢查,確保創(chuàng)建的bean是符合要求的,這些我們就不贅述了。
言歸正傳,細(xì)心的你一定發(fā)現(xiàn),創(chuàng)建bean時(shí)主要是從RootBeanDefinition mbd這個(gè)參數(shù)獲取bean的相關(guān)信息的,其實(shí)這就是大名鼎鼎的BeanDefinition,其中封裝了關(guān)于bean的元數(shù)據(jù)信息,關(guān)于BeanDefinition,后續(xù)我們會(huì)單獨(dú)講解,這里我們先理解為bean的元數(shù)據(jù)信息即可。那么這些元數(shù)據(jù)信息是什么時(shí)候解析的呢?
這就要提到Spring的類(lèi)掃描了,其大致流程是:通過(guò)ASM字節(jié)碼技術(shù)掃描所有的類(lèi) -> 找出加了@Compont注解的(簡(jiǎn)單理解) -> 封裝成BeanDefinition -> 存放到集合中。后續(xù)再實(shí)例化bean的時(shí)候,就可以遍歷這個(gè)集合,獲取到BeanDefinition,然后進(jìn)行bean的創(chuàng)建了。
關(guān)于處理類(lèi)掃描的ConfigurationClassPostProcessor后置處理器以及ConfigurationClassParser和ComponentScanAnnotationParser掃描器的具體細(xì)節(jié),后續(xù)我們單獨(dú)講解,和本章節(jié)關(guān)系不大,我們先簡(jiǎn)單理解即可。
2.2 實(shí)例化后回調(diào)
?在前面的章節(jié)我們分析過(guò):在容器中的bean實(shí)例化,放到單例池中之后,bean在創(chuàng)建階段的生命周期就正式完成,進(jìn)入使用中階段,開(kāi)啟對(duì)完服務(wù)之路。確實(shí),這就是創(chuàng)建bean的全過(guò)程,如果有小伙伴看過(guò)筆者之前的聊Spring事件的那篇文章(聊透Spring事件機(jī)制),會(huì)發(fā)現(xiàn)對(duì)于@EventListener處理器的識(shí)別注冊(cè),是在afterSingletonsInstantiated階段完成的。其實(shí)這里也是一個(gè)拓展點(diǎn),我們完全可以實(shí)現(xiàn)SmartInitializingSingleton#afterSingletonsInstantiated(),在bean初始化完成后會(huì)回調(diào)該方法,進(jìn)而觸發(fā)我們自己的業(yè)務(wù)邏輯,故這里我們單獨(dú)說(shuō)一下。不清楚的小伙伴請(qǐng)移步先去了解一下哦。
2.3 bean的銷(xiāo)毀階段
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...省略代碼
try {
// 為bean注冊(cè)DisposableBean,在容器關(guān)閉時(shí),調(diào)用destory()
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
復(fù)制代碼
?在創(chuàng)建bean的時(shí)候,會(huì)判斷如果bean是DisposableBean、AutoCloseable的子類(lèi),或者有destroy-method等,會(huì)注冊(cè)為可銷(xiāo)毀的bean,在容器關(guān)閉時(shí),調(diào)用對(duì)應(yīng)的方法進(jìn)行bean的銷(xiāo)毀。
網(wǎng)站名稱(chēng):聊透Spring bean的生命周期
標(biāo)題鏈接:http://fisionsoft.com.cn/article/ccsdcej.html


咨詢(xún)
建站咨詢(xún)
