Spring Bean生命周期:Bean的初始化阶段
【Spring Bean 生命周期系列】传送门
1、Spring Bean生命周期: Bean元信息的配置与解析阶段
2、Spring Bean生命周期: Bean的注册
3、Spring Bean生命周期: BeanDefinition的合并过程
4、Spring Bean生命周期: Bean的实例化
5、Spring Bean生命周期:属性赋值阶段
6、Spring Bean生命周期:Bean的初始化阶段
写在前面
注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE
前言
接着上节继续分析,上节说了Bean属性赋值的过程,这节就聊一下初始化Bean的过程
initializeBean
方法主要有四块内容
- Bean Aware方法回调
- BeanPostProcessor 初始化前回调
- 执行初始化方法
- BeanPostProcessor 初始化后回调
下面我们就按照这个顺序跟着源码逐块分析
Bean Aware方法回调
private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {//如果当前Bean实现了BeanNameAware,则将beanName通过回调传给当前Beanif (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}//如果当前Bean实现了BeanClassLoaderAware,则将BeanClassLoader通过回调传给当前Beanif (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}//如果当前Bean实现了BeanFactoryAware,则将BeanFactory通过回调传给当前Beanif (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}
这个方法主要实现了BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
三个Aware接口的回调。
下面就举例演示下
public class BeanAwareDemo implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(BeanAwareDemo.class);context.refresh();BeanAwareDemo bean = context.getBean(BeanAwareDemo.class);System.out.println("beanFactory==>" + bean.beanFactory);System.out.println("beanName==>" + bean.beanName);System.out.println("classLoader==>" + bean.classLoader);context.close();}private ClassLoader classLoader;@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {this.classLoader = classLoader;}private BeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}private String beanName;@Overridepublic void setBeanName(String name) {this.beanName = name;}
}
输出结果:
beanFactory==>org.springframework.beans.factory.support.DefaultListableBeanFactory@458c1321
beanName==>beanAwareDemo
classLoader==>sun.misc.Launcher$AppClassLoader@18b4aac2
看到这可能有同学会想:“那我平时经常用的ApplicationContextAware
是什么时候,在哪里被回调的呢?”
我:别着急,剩下的一些常用Aware接口的回调时机、在哪里回调,我们先不再这里展开了,以后有时间了单独拿出来讨论。
Bean初始化前后阶段
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//省略分析过的代码Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//初始化前回调wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//执行初始化方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {//省略异常信息}if (mbd == null || !mbd.isSynthetic()) {//初始化后回调wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
这里呢,为了方便说明,将Bean初始化前后放到一起来分析了。
经过我们前面章节的分析,我们对BeanPostProcessor
这个后置处理器也有了一些认识了。主要是通过postProcessBeforeInitialization
、postProcessAfterInitialization
两个方法在Bean初始化前与后对Bean进行些修饰。
一起来看下这两个方法吧!
//初始化前回调
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {//将原始Bean对象存一份Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName); // 如果有回调函数 返回null了,那么依然使用原始的Bean对象if (current == null) {return result;}//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理result = current;}return result;}//初始化后回调@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {//将原始Bean对象存一份Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);// 如果有回调函数 返回null了,那么依然使用原始的Bean对象if (current == null) {return result;}//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理result = current;}return result;}
这里不再给出栗子了,有兴趣的小伙伴可以去BeanPostProcessor浅析看一下
Bean 初始化方法
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {//判断当前Bean是否实现了InitializingBeanboolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {//省略日志输出//if条件成立 是Java安全代码逻辑可忽略,与else代码段实质操作一致if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 如果Bean实现了InitializingBean,那么这里回调afterPropertiesSet方法((InitializingBean) bean).afterPropertiesSet();}}//如果mbd不为空 且bean类型不是NullBeanif (mbd != null && bean.getClass() != NullBean.class) {//获取InitMethod方法名String initMethodName = mbd.getInitMethodName();//条件成立:1、存在initMethod方法 2、当前Bean不是InitializingBean或initMetodName不等于afterPropertiesSet 3、不是外部管理的initMethodsif (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// 那么执行自定义InitMethod方法,根据方法名获取Method 反射调用invokeCustomInitMethod(beanName, bean, mbd);}}}
上面给出了afterPropertiesSet
、initMethod
两个初始化方法的调用过程及调用顺序,这里的initMethod
与@Bean中initMethod属性是一致的。
有的小伙伴可能会说了:“那我平时还经常使用一种别的初始化方法呢?是用@PostConstruct
”标注的,它不是在这里被调用吗?那它是在哪里被调用的?"
我: 还记得BeanPostProcessor浅析章节吗? 我们在那个章节介绍了一些常用的BeanPostProcessor,其中@PostConstruct就是在CommonAnnotationBeanPostProcessor
被调用的。
其实CommonAnnotationBeanPostProcessor
继承自InitDestroyAnnotationBeanPostProcessor
,确切地说是两个类联合起来完成对@PostConstruct的解析和方法调用
还记得上面
Spring Bean生命周期:Bean的初始化阶段相关推荐
- Spring Bean生命周期: Bean的实例化
[Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...
- springboot学习:bean生命周期
1.bean 生命周期 bean创建-初始化-销毁 构造(对象创建): 单实例:在容器启动的时候创建对象; 多实例:在每次获取的时候创建对象: 初始化: 对象创建完成,并赋值好,调用初始化方法 销毁: ...
- Spring生命周期Bean初始化过程详解
Spring生命周期Bean初始化过程详解 Spring 容器初始化 Spring Bean初始化 BeanFactory和FactoryBean 源码分析 Bean的实例化 preInstantia ...
- 《Spring揭秘》——IOC梳理2(容器启动,bean生命周期)
IoC容器背后的秘密 主要分为两个阶段:容器启动阶段.Bean实例化阶段. 容器启动阶段: 容器需要依赖某些工具类(BeanDefinitionReader)对加载的Configuration Met ...
- 3、Spring Bean生命周期
Spring Bean的生命周期只有四个阶段,每个阶段又有对应的扩展点,如下: 实例化 Instantiation 属性赋值 Populate 初始化 Initialization 销毁 Destru ...
- Spring Bean生命周期,就像人的一生
这篇我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 1 简单说说IoC和Bean IoC,控制反转,想必大家都知道,所谓的控制反转,就是把new对象的权利交给容器,所有的对 ...
- 【Spring】- Bean生命周期
2019独角兽企业重金招聘Python工程师标准>>> Spring Bean的生命周期: bean对象实例化 属性注入 beanfactory ApplicationContext ...
- Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02
文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...
- Spring Bean默认配置为单实例 Spring Bean生命周期
2019独角兽企业重金招聘Python工程师标准>>> Spring 的Bean默认的是单例的. 如果不想单例需要如下配置: <bean id="user" ...
最新文章
- 机器学习(10)随机森林(预测泰坦尼克号旅客存活率)
- 怎么让修改的html持久化_redis持久化机制
- vue2.0搭建vue手脚架(vue-cli)
- 牛客 - 小朋友你是否有很多问号(容斥+组合数学)
- windows下连接db2数据库
- 指令 出厂_口碑营销_南澳出口木箱出厂价
- linux 批量替换文件内容及查找某目录下所有包含某字符串的文件(批量修改文件内容)...
- IIS经典模式与集成模式
- RDP大屏幕报表sql问题
- Activiti7工作流+Springboot快速入门
- 1.1信息安全基础概念
- Tumblr,instapaper分享
- 失眠就吃安眠药真的好吗?好心情送你沾枕到天亮的诀窍
- 基于matlab的脑瘤mr图像处理_基于电势能改进的区域生长脑肿瘤图像分割
- js的alert弹框中怎么写html,JavaScript实现alert弹框效果
- hdu 1429	胜利大逃亡(续)
- pythonapp自动化_基于python的App UI自动化环境搭建
- OpenStack核心组件原理与应用之Keystone
- 多元线性回归的spss应用
- 转载一篇关于泰迪很好的文章