你有了解Spring中Bean的生命周期吗?可能大多数的人给我一样,对于Spring本身知之甚少。
我们仅限于在工作中如何使用Spring的Bean,使用起来Bean 是如何如何好用?但是我们好像很少去思考它都做了些什么?
当然学习是一个漫长且持久的过程,我们只能一点点积累,从而积少成多。
本章节主要来学习下Spring中Bean的生命周期。
我们在具体聊Spring Bean的生命周期之前,我们先聊一个概念:Spring Bean的作用域。它是什么?能被用来干嘛?不懂就查。
Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。
比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有一份,它是全局共享的,当有人修改了这个值之后,那么另一个人读取到的就是被修改后的值。
Spring框架支持以下五种Bean的作用域:
org.springframework.context.support.AbstractApplicationContext.refresh()
--> org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization // 初始化bean(延迟加载除外)
--> org.springframework.beans.factory.config.ConfigurableListableBeanFactory.preInstantiateSingletons()
--> org.springframework.beans.factory.support.AbstractBeanFactory.getBean
--> org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean
--> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean // 创建 bean(实例化 bean)
--> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
Spring Bean的初始化是在Spring 容器 refresh() 时进行的,Spring 容器 refresh 时会调用 finishBeanFactoryInitialization() 来初始化所有非延迟加载的 bean。
我们启动本地项目,在上述层级结构上打上端点,结合源码,我们来看下Bean的创建过程。
你会发现,在真正createBean之前,还有一个方法doGetBean,它是干嘛的?
我们进一步深入分析看下:
1、doGetBean 获取Bean
以上doGetBean方法简单的流程图,结合源码具体说明如下:
1、获取真正的BeanName:方法transformedBeanName()
参数 name,不一定是 beanName,可能是 aliasName,也有可能是 FactoryBean(带“&”前缀),所以这里需要调用 transformedBeanName()方法对 name 进行一番转换。
那么alias最终会是:{“whiteApple3”:“whiteApple2”} {“whiteApple3”:“whiteApple1”}
2、获取缓存中的单例:getSingleton()
3、isPrototypeCurrentlyInCreation方法:如果scope是prototype 并且还在创建中,直接抛出异常
4、getParentBeanFactory() 获取当前BeanFactory的parentBeanFactory
以上doCreateBean方法简单的流程图,结合源码具体说明如下:
1、mbd.isSingleton() 判断是否是单例,如果是,则需要在缓存factoryBeanInstanceCache 中把beanName对应的数据remove掉。
2、BeanWrapper为空的情况下 调用createBeanInstance创建bean实例。
默认使用无参的构造方法:clazz.getDeclaredConstructor()
默认使用无参的构造方法:clazz.getDeclaredConstructor()
如下图所示:
查到指定的注解注释的属性和方法,最后都封装到InjectionMetadata返回。
4、如果earlySingletonExposure为true,调用addSingletonFactory缓存数据。哈哈哈哈哈哈哈哈哈哈哈哈哈
为了解决循环引用问题,后续在单写章节聊这个点。
5、调用populateBean方法进行属性赋值
因为步骤3中applyMergedBeanDefinitionPostProcessors方法中,已经完成了属性数据的解析,当前此方法直接获取封装好的数据,进行处理即可。
例如:CommonAnnotationBeanPostProcessor.postProcessProperties()
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//获取类中封装好的属性元数据
InjectionMetadata metadata = this.findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
return pvs;
} catch (Throwable var6) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", var6);
}
}
6、调用initializeBean方法进行初始化
7、bean的销毁:ConfigurableApplicationContext.close()
public void close() {
synchronized(this.startupShutdownMonitor) {
this.doClose();
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
} catch (IllegalStateException var4) {
}
}
}
}
8、扩展点:BeanPostProcessor
我们在学习的过程中,发现了很多继承BeanPostProcessor类的子类,因为spring bean在创建过程中不同的阶段都会回调BeanPostProcessor组件的方法,这样就可以达到扩展的目的。因为只要你自己实现了BeanPostProcessor组件,就可以在生命周期的不同阶段可以对你的bean进行不同的操作,达到自己的目的。