背景

spring 使用了 IOC(控制反转)模型,让对象存储在 spring 容器中,每当我们要使用对象时,就可以通过依赖注入的方式从容器中获取 bean 对象。

由于 bean 对象是交给容器来管理,故有了生命周期的概念。这个生命周期不仅有容器的生命周期,还有 bean 对象的生命周期。

spring 的容器

spring 的容器有 BeanFactory(bean 工厂)和 ApplicationContext (应用上下文)两个容器。

区别:

  • beanfactory 只提供了基础的 bean 存储功能和依赖注入功能,版本控制功能。
  • applicationContext 继承了 beanfactory 的所有特性,还提供了大量的扩展,根据配置实现国际化,事件传播,资源加载等,还支持 J2EE 的一些特性。
  • BeanFactory 的 bean 是延时加载的,即创建容器时并不会实例化扫描到的对象,而是当被注入使用时才实例化。
  • ApplicationContext 是非延时加载,即初始化容器是就把 bean 对象也初始化了。

bean 的生命周期

  1. 实例化 spring 容器(applicationContext)
  2. 扫描符合 springbean 规则的类(规则:@ComponentScan,@Bean 等)
  3. 遍历扫描的类,将其封装到一个 beanDefinitionMap 对象中。(可以理解为图纸,里面存放了 bean 类的信息,例如抽象类,懒加载等)
  4. 如果使用到了 BeanFactoryProcessor 类,则会来干预原先的类定义,即干预图纸。
  5. 遍历 beanDefinitionMjap(图纸),获取到类的信息,在通过算法推断出该类合理的构造方法。
  6. 通过这个构造方法反射出一个对象。
  7. 三级缓存,执行循环依赖注入。(下面会解释)
  8. 执行 aware 接口(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware)
  9. 若 bean 关联了 BeanPostProcessor 接口,则此时会调用 postProcessBeforeInitialization 方法,主要是对 bean 的内容进行更改。
  10. 执行 bean 的初始化方法 init-method。
  11. 若 bean 关联了 BeanPostProcessor 接口,则还会调用 postProcessAfterInitialization 方法。
  12. 执行 aop 动态代理(例如事件分发,发布监听等)
  13. 将 bean 放入单例池 singletonobjects 中。
  14. 销毁,destroy()。

springboot 把bean存进session里_ioc

依赖注入

依赖注入也是循环依赖,是两个或两个以上的 bean 互相持有对方,形成闭环。比如 A 依赖 B,B 又依赖 A。

springboot 把bean存进session里_ioc_02

问题:当 A 初始化时,由于没有 B,故初始化不了;当 B 初始化时,由于没有 A,也初始化不了,造成了死锁。

那么如何才能在 spring 容器中创建这两个 bean 对象呢?spring 采用了三级缓存的概念。

三级缓存:

  1. singletonFactories:单例对象工厂,生产 bean 对象的地方。
  2. earlySingletonObjects:提前曝光的单例对象(还没初始化完,但已经有了雏形)
  3. singletonObjects:可以直接拿来用的缓存。

步骤:

  1. A 初始化时,就会在工厂中实例化并放入到提前曝光的单例对象缓存中。
  2. A 要注入属性 B 时,由于找不到 B 对象,故要先创建 B。
  3. B 初始化时,也会在工厂中实例化后放入到提前曝光的单例对象缓存中。
  4. B 要注入属性 A,先从单例对象缓存中找,没找到,再从提前曝光的缓存中找,找到了 A,就把 A 注入。
  5. B 完成创建后再创建 A。
  6. 由于 B 注入的是 A 的引用,A 在初始化后的操作对 B 也是可见的。