小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
17.SpringBean 的生命周期
- 1. 实例化
- a. 通过反射推断构造函数进行实例化。
- b. 通过实例工厂、静态工厂等方法进行实例化。
- 2. 属性填充
- a. 解析自动装配(自动装配方式:byname、bytype、constractor none @AutoWired)。
- b. 解决Bean的循环依赖。
- 3. 初始化
- a. 调用XXXAware方法,如果有实现的话才会调用。(常见的Aware方法有三个:
BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。)。 - b. 调用初始化生命周期回调(三种)如果实现的话才会调用。
- a. 调用XXXAware方法,如果有实现的话才会调用。(常见的Aware方法有三个:
- 4. 销毁
- a. 在Spring容器关闭的时候进行调用。
- b. 调用销毁生命周期回调(三种)如果实现的话才会调用。
18. Spring是如何解决Bean的循环依赖的?
使用三级缓存,也就是三个map 一级缓存:储存完整的bean 二级缓存:储存创建好的动态代理。(该级缓存作用:避免多重循环依赖,重复创建动态代理) 三级缓存:
- 缓存是函数接口:通过lambda把方法传进去(把Bean的实例和Bean名字传进去(aop创建)
- 不会立即调:(如果在实例化后立即调用的话:所有的aop不管bean是否循环依赖都会在实例化后创建proxy,正常Bean其实spring还是希望遵循生命周期在初始化创建动态里,只能循环依赖才创建)
- 会在ABA(第二次getBean(A)才会去调用三级缓存(如果实现了aop才会创建动态代理,如果没有实现依然返回的Bean的实例)
- 放入二级缓存(避免重复创建)
现有A,B两个bean互相调用,则它们在初始化的时候会发生以下事件。
graph TD
1.getBeanA --> 2.doGetBeanA --> 3.getSingletonA从缓存中读取 --> 此时去1级缓存中查找
3.getSingletonA从缓存中读取 --> 缓存中没有找到 --> 4.getSingletonA创建A --> 5.createBean和doCreateBean --> 6.实例化 --> 加入三级缓存
6.实例化 --> 7.属性赋值 --> 8.初始化 --> 9.getSingletonA从二级缓存中拿到Abean --> 10.addSingleton把创建好的ABean放入一级缓存在二三级缓存中删除ABean
7.属性赋值 --> 发现Bbean,去调用Bbean生成过程--> B.7.属性赋值 --> 从缓存逐层检测,在第三层中拿取A,创建动态代理后把A放入二级缓存 --> 创建B,并返回Bbean --> 7.属性赋值
2重同步锁,2次检查。
A实例化的时候,会锁住二级、三级缓存。(为啥不锁一级?因为会影响到性能,一级缓存中有许多已经实例化好了的bean) 参考17题中的图:
- 在第三步3.getSingletonA从缓存中读取bean的时候,会给二三级缓存加上同步锁。
- 然后在4-10步的时候,也给二三级缓存加上同步锁。如果此时有其他线程访问缓存获取bean,只能访问到一级缓存,然后阻塞。
- 当线程1完成bean创建,线程2继续访问二三级缓存,仍然访问不到线程1创建的Abean(Abean创建完成放在一级缓存中)。
- 线程2继续下一步,到第4步4.getSingletonB的时候,再去访问一次缓存,就能从一级缓存中拿到Abean