1、bean被创建保存到spring容器的过程
1、实例化 -> 获取对象;
2、填充属性;这里可能需要依赖其它的bean。
3、AOP代理对象替换;
4、加入单例池;
问题:
循环依赖怎么处理
ServiceA 中有属性ServiceB b;
ServiceB中有属性ServerA a;
如何打破循环?
在第1步中,aService实例化后存入到map中。在2.2步中,如果单例池中没有,再去查前面的map。这样就打破了无限循环逻辑。
如果循环依赖中的bean是需要做AOP替换的代理对象,问题又该如何解决?
需要提前进行AOP创建代理对象-早期对象。
2、spring容器启动过程中用到的三个map
1、单例池 singletoneObjects,存储完整的bean实例;
2、早期的单例池 earlySingletonObjects,用于解决AOP代理对象的问题;确保创建过程中的不完整的对象也是单例的。
3、singletonFactories,value是一个Function。
如果没有三级缓存singletonFactories,那么在创建AOP代理对象时就无法获取到原目标target普通对象。如果可以获取到到target对象,那么循环就会被打破,循环问题就解决了。
所以singletonFactories中的value其实是一个获取早期对象的函数,里面可能返回普通对象也可能返回AOP对象,但都是没有执行完完整实例化过程的对象(早期对象),这里设计比较巧妙。
3、为什么不先实例化所有的bean,再进行属性依赖注入?
Spring 容器在启动时不会立即实例化所有的 bean,因为这样做可能会创建许多不会被用到的 bean 实例,从而浪费内存和初始化时间。相反,Spring 容器按需创建 bean,即当应用程序请求一个 bean 时,容器才会创建它,并且如果该 bean 依赖其他 bean,则先实例化依赖的 bean。
这种懒加载(Lazy Loading)的策略使得容器更加高效,因为它只实例化必需的组件,从而节省资源。
也会存在构造注入的场景,所以这时也是先需要其它bean实例的。
3、哪些场景下Spring还是会报循环依赖的错误?
1、@Async + 循环依赖 。
解决:-> 添加@Lazy
2、循环依赖&唯一构造注入
根本无法实例化!因为构造函数中的逻辑循环了!
解决:改成属性注入而非构造!
学习资料参考: