注意点: toString()方法重写时需要注意:不能直接输出wife,输出wife.getName()。要不然会出现递归导致的栈内存溢堕落误。1.2 singletion 下的 set 注入下的 Bean 的循环依赖
简单来说:就是:singleton 优先被“曝光”,实例化和赋值是分开的,会优先把实例化的对象的地点曝光出来,因为在 singleton 单例模式下,bean 是唯一的一个,独一无二的,并且早晚都要举行赋值操作。提前曝光,背面再举行赋值也是无妨的。因为你弄来弄去,就是那唯一的一个 bean。不存在多个,不知道是哪一个的问题。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'husbandBean' defined in class path resource [spring.xml]: Cannot resolve reference to bean 'wifeBean' while setting bean property 'wife'特别的:当两个bean的scope都是prototype的时候,才会出现非常,如果此中任意一个是singleton的,就不会出现非常了。是此中的任意一个 就行,就不会出现非常了。如果是三个 bean 的话,那就需要此中的任意两个 是为singleton才行。
创建名为“husbandBean”的bean时堕落:请求的bean当前正在创建中:是否存在无法剖析的循环引用?通过测试得知,当循环依赖的所有Bean的scope="prototype"的时候,产生的循环依赖,Spring是无法解决的,会出现BeanCurrentlyInCreationException非常。
prototype下的 set 注入下的 Bean 的循环依赖;并不能解决循环依赖,缘故原由是:prototype 是多例的存在,多个 Bean 对象,不是唯一的一个Bean,无法确定是具体是哪个,Bean无法提前曝光。复制代码
- BeanCreationException 报错:当前的Bean正在处于创建中异常
缘故原由是:singleton 优先被“曝光”,实例化和赋值是分开的,会优先把实例化的对象的地点曝光出来,因为在 singleton 单例模式下,bean 是唯一的一个,独一无二的,并且早晚都要举行赋值操作。提前曝光,背面再举行赋值也是无妨的。因为你弄来弄去,就是那唯一的一个 bean。不存在多个,不知道是哪一个的问题。测试:当两个bean的scope都是prototype的时候,才会出现非常,如果此中任意一个是singleton的,就不会出现非常了。
复制代码
- addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
我们再来看,在该类中有这样一个方法 addSingletonFactory(),这个方法的作用是:将创建Bean对象的ObjectFactory对象提前曝光。这里我们Debug 调试看看。复制代码
- private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 一级缓存
- private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); 二级缓存
- private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 三级缓存
- 这个三个缓存都是Map集合
- Map集合的key 存储的都是bean的name(bean id)
- > 一级缓存存储的是:单例Bean对象,完整的单例Bean对象,也就是这个缓存中的Bean对象的属性都已经赋值了,是一个完整的Bean对象
- > 二级缓存存储的是: 早期的案例Bean对象,这个缓存中的单例Bean对象的属性灭有赋值,只是一个早期的实例对象
- > 三级缓存存储的是: 单例工厂对象,这个里面存储了大力的“工厂对象”,每一个单例Bean对象都会对应一个单例工厂对象。
- > 这个集合中存储的是,创建该单例对象时对应的那个单例工厂对象。
Spring只能解决setter方法注入的单例bean之间的循环依赖。ClassA依赖ClassB,ClassB又依赖ClassA,形成依赖闭环。Spring在创建ClassA对象后,不需要等给属性赋值,直接将其曝光到bean缓存当中。在剖析ClassA的属性时,又发现依赖于ClassB,再次去获取ClassB,当剖析ClassB的属性时,又发现需要ClassA的属性,但此时的ClassA已经被提前曝光加入了正在创建的bean的缓存中,则无需创建新的的ClassA的实例,直接从缓存中获取即可。从而解决循环依赖问题。2. 总结:
3. 末了:
- Bean的循环依赖:A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你,你也依赖我。
- singletion 下的 set 注入下的 Bean 的循环依赖可以或许被解决。主要缘故原由是:在这个 singleton 单例模式下,在Spring 容器中的 bean 对象是独一无二的对象,是唯一的一个。同志在该 singleton 单例模式下:Spring 对 Bean 的管理主要分为清晰的两个阶段
核心解决方案是:实例化对象和对象的属性赋值分为两个阶段来完成,并不是一次性完成的。
- 第一个阶段:在Spring 容器加载的时候,实例Bean ,只要此中任意一个 Bean 实例化之后,马上举行一个“曝光” (注意:曝光不等于属性赋值,曝光了,但是属性并没有附上值的)
- 第二个阶段:Bean “曝光”之后,再举行属性的赋值操作(调用 set()方法实现对属性的赋值操作)
- prototype下的 set 注入下的 Bean 的循环依赖;并不能解决循环依赖,缘故原由是:prototype 是多例的存在,多个 Bean 对象,不是唯一的一个Bean,无法确定是具体是哪个,Bean无法提前曝光。
- 特别的:当两个bean的scope都是prototype的时候,才会出现非常,如果此中任意一个是singleton的,就不会出现非常了。是此中的任意一个 就行,就不会出现非常了。如果是三个 bean 的话,那就需要此中的任意两个 是为singleton才行。
- 至于,三个 Bean ,需要任意两个为 singleten ,才不会报非常,就大家自行测试了。理论上就是:n 个 就需要 N-1个为 singleten 。
- 注意报错信息:org.springframework.beans.factory.BeanCreationException: 当前的Bean正在处于创建中非常
- singleton下的构造注入产生的循环依赖;是基于构造注入(举行赋值),很明显,要调用构造方法举行赋值就一定要完完整整的举行一次性赋值+实例化,没有分段的,以是会产生循环依赖并且无法解决的,
- Spring 解决循环依赖的原理(源码剖析):一级缓存,二级缓存,三级缓存的存在。提前“曝光”机制
“在这个末了的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上汲取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的范畴奋斗。感谢你们,我们总会在某个时刻再次相遇。”
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |