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

相信大家也应该想到了,A对象填充属性时必然发现依赖了B对象,此时就将转头创建B,在创建B时同样会经历以上步骤,此时就该B对象填充属性了,这时,又将要转头创建A,那么,现在会有什么不一样的地方呢?我们看看getBean的逻辑吧

doGetBean

protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly){ // 此时beanName为A String beanName = transformedBeanName(name); // 尝试从三级缓存中获取bean,这里很关键 Object sharedInstance = getSingleton(beanName); } protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 从单例缓存池中获取,此时仍然是取不到的 Object singletonObject = this.singletonObjects.get(beanName); // 获取不到,判断bean是否正在创建,没错,此时A确实正在创建 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 由于现在仍然是在同一个线程,基于同步锁的可重入性,此时不会阻塞 synchronized (this.singletonObjects) { // 从早期对象缓存池中获取,这里是没有的 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 从三级缓存中获取回调函数,此时就获取到了我们在创建A时放入的回调函数 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 调用回调方法获取早期bean,由于我们现在讨论的是普通对象,所以返回原对象 singletonObject = singletonFactory.getObject(); // 将早期对象放到二级缓存,移除三级缓存 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } // 返回早期对象A return singletonObject; }

震惊!此时我们就拿到了A的早期对象进行返回,所以B得以被填充属性,B创建完毕后,又将返回到A填充属性的过程,A也得以被填充属性,A也创建完毕,这时,A和B都创建好了,循环依赖问题得以收场~

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

普通Bean和普通Bean之间的问题就到这里了,不知道小伙伴们有没有晕呢~

2. 普通Bean和代理对象

普通Bean和代理对象之间的循环依赖与两个普通Bean的循环依赖其实大致相同,只不过是多了一次动态代理的过程,我们假设A对象是需要代理的对象,B对象仍然是一个普通对象,然后,我们开始创建A对象。

刚开始创建A的过程与上面的例子是一模一样的,紧接着自然是需要创建B,然后B依赖了A,于是又倒回去创建A,此时,再次走到去缓存池获取的过程。

// 从三级缓存中获取回调函数 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 调用回调方法获取早期bean,此时返回的是一个A的代理对象 singletonObject = singletonFactory.getObject(); // 将早期对象放到二级缓存,移除三级缓存 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); }

这时就不太一样了,在singletonFactory.getObject()时,由于此时A是需要代理的对象,在调用回调函数时,就会触发动态代理的过程

AbstractAutoProxyCreator#getEarlyBeanReference

public Object getEarlyBeanReference(Object bean, String beanName) { // 生成一个缓存Key Object cacheKey = getCacheKey(bean.getClass(), beanName); // 放入缓存中,用于在初始化后调用该后置处理器时判断是否进行动态代理过 this.earlyProxyReferences.put(cacheKey, bean); // 将对象进行动态代理 return wrapIfNecessary(bean, beanName, cacheKey); }

此时,B在创建时填充的属性就是A的代理对象了,B创建完毕,返回到A的创建过程,但此时的A仍然是一个普通对象,可B引用的A已经是个代理对象了,不知道小伙伴看到这里有没有迷惑呢?

不急,让我们继续往下走,填充完属性自然是需要初始化的,在初始化后,会调用一次后置处理器,我们看看会不会有答案吧

初始化 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { //...省略前面的步骤... // 调用初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); // 处理初始化后的bean wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }

在处理初始化后的bean,又会调用动态代理的后置处理器了

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); // 判断缓存中是否有该对象,有则说明该对象已被动态代理,跳过 if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }

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

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