本文对Spring初始化过程、bean的声明周期进行梳理,同时为了容易记忆,会将对Spring的常见使用和源码结合
spring的IOC容器初始化入口,位于org.springframework.context.support.AbstractApplicationContext#refresh方法
几个重要的节点
(1)对beanDefination的自定义拦截和修改,由invokeBeanFactoryPostProcessors方法触发,执行所有BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,最常用的是org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry,这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解(参考ConfigurationClassPostProcessor —— Spring中最!最!最!重要的后置处理器!没有之一!!! - 掘金)
在postProcessBeanDefinitionRegistry方法内部有一个重要的回调,即ImportBeanDefinitionRegistrar的registerBeanDefinitions,实际应用经常通过实现该回调来将自定义的beandefinition注入容器,比如dubbo的DubboComponentScanRegistrar类
该方法的importingClassMetadata参数可用来获取指定注解的信息,比如DubboComponentScanRegistrar就用它获取存在DubboComponentScan注解的包位置,以进行bean的初始化扫描
(2)BeanFactory内部,即invokeBeanFactoryPostProcessors方法调用,调用容器中定义的BeanFactoryPostProcessor的postProcessBeanFactory方法,根据官方注解,此时方法入参里的beanFactory中所有bean已经加载但未初始化
可在方法内部获取bean的定义并记录,如下图
另一个常见的用法是通过beanFactory.registerSingleton方法将自定义的bean(如rpc的server)注入容器,注意注入之前必须将bean完全初始化,调用registerSingleton后bean不会收到任何初始化和销毁的回调,AOP也会失效(参考spring动态注册bean会使AOP失效? - 腾讯云开发者社区-腾讯云)
(3)注册BeanPostProcessor
(4)接下来最重要的入口在BeanFactory的preInstantiateSingletons方法的调用,最重要的bean的初始化逻辑均在该方法内部,注意spring初始化过程的异常在这个方法抛出,过去在工作中这类异常无日志记载,往往需要使用arthas监听这个方法的执行才能获取异常
该方法对factoryBean和普通bean的初始化进行了区分处理
本文暂时只关注普通bean的初始化逻辑
(5)普通bean初始化逻辑的BeanFactory.getBean直接调用了AbstractBeanFactory#doGetBean方法,这是初始化一个bean的总入口。
首先从熟悉的三级缓存中加载,如bean已在缓存则返回 ,三级缓存原理参考 spring5 源码深度解析-----IOC 之 循环依赖处理 - chen_hao - 博客园
如bean未在缓存中,首先加载依赖的bean,同样调用BeanFactory.getBean方法,走上面同样的逻辑
加载完依赖的bean,根据bean作用域(单例、protype等)的不同,走不同的初始化逻辑
(6)本文暂只关注单例情况下的初始化方法,DefaultSingletonBeanRegistry#getSingleton
该方法主要做了两件事,一是标记bean在创建中,用于后续循环依赖的解决
二是真正的bean创建过程,入口在AbstractAutowireCapableBeanFactory#createBean
注意这里有一个重要的resolveBeforeInstantiation调用,这里允许BeanPostProcessor生成proxy类代替原始的bean,也就是AOP对象注入的地方
接着开始最重要的bean创建过程
主要入口在AbstractAutowireCapableBeanFactory#doCreateBean,实现创建一个bean实例(没有特殊策略就通过默认构造函数来反射创建)
接着判断当前bean是否还未创建完成就曝光,如是生成一个返回上步创建的bean对象的工厂对象放入第三级缓存中,供依赖它的bean使用
接着前置工作都已完成,要真正进入bean的创建
普通bean的创建分两大部分
- populateBean:给bean注入属性值,还包括autowire注入解析、依赖检测等,参考Spring源码之bean的属性填充populateBean方法解读_桐花思雨的博客-CSDN博客_populatebean
- 完成属性值注入后,调用AbstractAutowireCapableBeanFactory#initializeBean执行各种初始化回调
至此单例bean创建完成,回到单例bean的入口DefaultSingletonBeanRegistry#getSingleton,将创建完成的bean从二三级缓存删除,放入一级缓存