Spring源码分析之循环依赖及解决方案 (4)

现在,就走到了我们自定义的getObject方法,由于我们调用了context.getBean("normalBeanB", NormalBeanB.class),此时,将会去创建B对象,在创建过程中,先将B的早期对象放入三级缓存,紧接着填充属性,发现依赖了A对象,又要倒回来创建A对象,从而又回到上面的逻辑,再次调用我们自定义的getObject方法,这个时候会发生什么呢?

又要去创建B对象...(Spring:心好累)

但是!此时我们在创建B时,是直接通过getBean在缓存中获取到了B的早期对象,得以返回了!于是我们自定义的getObject调用成功,返回了一个完整的A对象!

但是此时FactoryBean的缓冲中还是什么都没有的。

// 又从缓存中取了一次 Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; }

这一次取alreadyThere必然是null,流程继续执行,将此时将获取到的bean放入缓存

this.factoryBeanObjectCache.put(beanName, object);

从FactoryBean获取对象的流程结束,返回到创建B的过程中,B对象此时的属性也得以填充,再返回到第一次创建A的过程,也就是我们第一次调用自定义的getObject方法,调用完毕,返回到这里

// 获取bean,调用factoryBean的getObject() object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere;

那么,此时this.factoryBeanObjectCache.get(beanName)能从缓冲中拿到对象了吗?有没有发现,拿到了刚刚B对象填充属性时再次创建A对象放进去的!

所以,明白这里为什么要再次从缓存中获取了吧?就是为了解决由于循环依赖时调用了两次自定义的getObject方法,从而创建了两个不相同的A对象,保证我们返回出去的A对象唯一!

怕小伙伴晕了,画个图给大家

Spring源码分析之循环依赖及解决方案

5. 工厂Bean与工厂Bean之间

我们已经举例4种循环依赖的栗子,Spring都有所解决,那么有没有Spring也无法解决的循环依赖问题呢?

有的!就是这个FactoryBean与FactoryBean的循环依赖!

假设工厂对象A依赖工厂对象B,工厂对象B依赖工厂对象A,那么,这次的栗子会是什么样呢?

普通对象

public class NormalBeanA { private NormalBeanB normalBeanB; public void setNormalBeanB(NormalBeanB normalBeanB) { this.normalBeanB = normalBeanB; } } public class NormalBeanB { private NormalBeanA normalBeanA; public void setNormalBeanA(NormalBeanA normalBeanA) { this.normalBeanA = normalBeanA; } }

工厂对象

@Component public class FactoryBeanA implements FactoryBean<NormalBeanA> { @Autowired private ApplicationContext context; @Override public NormalBeanA getObject() throws Exception { NormalBeanA normalBeanA = new NormalBeanA(); NormalBeanB normalBeanB = context.getBean("factoryBeanB", NormalBeanB.class); normalBeanA.setNormalBeanB(normalBeanB); return normalBeanA; } @Override public Class<?> getObjectType() { return NormalBeanA.class; } } @Component public class FactoryBeanB implements FactoryBean<NormalBeanB> { @Autowired private ApplicationContext context; @Override public NormalBeanB getObject() throws Exception { NormalBeanB normalBeanB = new NormalBeanB(); NormalBeanA normalBeanA = context.getBean("factoryBeanA", NormalBeanA.class); normalBeanB.setNormalBeanA(normalBeanA); return normalBeanB; } @Override public Class<?> getObjectType() { return NormalBeanB.class; } }

首先,我们开始创建对象A,此时为调用工厂对象A的getObject方法,转而去获取对象B,便会走到工厂对象B的getObject方法,然后又去获取对象A,又将调用工厂对象A的getObject,再次去获取对象B,于是再次走到工厂对象B的getObject方法......此时,已经历了一轮循环,却没有跳出循环的迹象,妥妥的死循环了。

我们画个图吧~

Spring源码分析之循环依赖及解决方案

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgjfgf.html