在 spring 学习之源码分析 –AbstractApplicationContext 之 refresh 中,提及了容器初始化时调用 createBean 创建 bean,但是没有细讲,这边就详细的讲解一下。
createBean
- 解析 class 类型
- 如果有 lookup-method 和 replaced-method 属性先处理。如果有某个属性,就调用动态代理,进行相应的拦截。另外,有些方法可能存在重载的情况,在这里也会一并处理了,如果只有一个方法名,会标记为没有重载,这样后面调用方法的时候,就可以直接调用了。
- resolveBeforeInstantiation,先判断是否解析过了,如果没有,看看 InstantiationAwareBeanPostProcessor 能不能生成 bean–applyBeanPostProcessorsBeforeInitialization,这个 bean 不一定是普通的 bean,也可能是动态代理或者其他方式生成的 bean。如果可以生成 bean,就标志位解析过了,并且调用后置处理器处理 –applyBeanPostProcessorsAfterInitialization。
- 如果没有生成,调用 doCreateBean 方法,下面我们看看这部分内容
doCreateBean
doCreateBean 方法
- 如果是单例,取出 bean 并清空缓存。
- 如果取出的 bean 为空,实例化 bean,具体实例化过程下面讲解。
- 创建后,MergedBeanDefinitionPostProcessor 进行后置处理,这个 MergedBeanDefinitionPostProcessor 包括 AutowiredAnnotationBeanPostProcessor 等。
- 依赖处理
- 实例化后,对 bean 各个属性进行赋值。见 populateBean。
- 赋值后,调用 init 方法,InitializingBean 这些。见 initializeBean
- 再检查一下依赖,看看是不是初始化方法改变了什么
- 根据 scope 注册 DisposableBean,registerDisposableBeanIfNecessary 方法
createBeanInstance
createBeanInstance 方法
- 先检查是否有类的访问权限,如果没有权限,只能抛异常了
- 看看有没有 Supplier 回调,如果有回调,就让别人回调创建
- 看看有没有工厂方法回调,如果有回调,就让工厂方法回调创建
- 如果没有其他人插手了,就开始自己创建了。实例化类要么有参构造要么无参构造,由于每次解析很耗性能,所以要把构造结果缓存起来。既然有缓存,当然是先查询是否有缓存,如果有,再根据缓存选择无参构造还是有参构造。
- 如果缓存没有,就去解析,解析后缓存结果,以及选择无参构造还是有参构造。
populateBean
populateBean 方法
实例化了 bean,给 bean 的属性赋值。
- 先判断是否有属性需要赋值
- InstantiationAwareBeanPostProcessor 后置处理,是否继续填充属性。我们可以看到,spring 在很多阶段做了很多这类后置处理。
- 根据名称或类型,获取需要注入的 bean。根据 name 比较简单,就是 getBean,根据类型解析就有点复杂了。
- 赋值前,InstantiationAwareBeanPostProcessor 后置处理验证属性
- 依赖检查
- 赋值
initializeBean
initializeBean 方法
bean 构造完了,也给各个属性赋值了,先在就看看有没有初始化方法了。
- Aware 处理,也就是说,如果实现了 Aware 接口,会注入一些属性给这些 bean
- 后置处理器处理,调用 BeanPostProcessor 的 postProcessBeforeInitialization
- invokeInitMethods,如果实现了 InitializingBean 接口,就调用他的 afterPropertiesSet 方法,如果有自定义方法,就继续调用自定义方法。例子请查看 spring 学习之 bean 生命周期的管理