《Java后端知识体系》系列之从源码让你明白Spring是如何解决循环依赖的?

怎么出现循环依赖的异常呢?写了一个例子来实现?

@Component
public class ModelA {
    private ModelB modelB;
    @Autowired
    public ModelA(ModelB modelB){
        this.modelB = modelB;
    }
}
@Component
public class ModelB {
    private ModelA modelA;
    @Autowired
    public ModelB(ModelA modelA){
        this.modelA = modelA;
    }
}
@Configuration
@ComponentScan(basePackages = { "com.example.demo.cycle" })
public class Test {
    public static void main(String[] args) {

    }
}
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes = { Test.class })

public class UnitTest {
    @org.junit.Test
    public void givenCircularDependency_whenConstructorInjection_thenItFails() {
        
    }
}

既然会出现这种问题,那么Spring又是如何解决的呢?

处理条件

  • 循环依赖的Bean是单例的
  • 依赖注入的方式不能是构造函数注入的

解决方式

直接上源码,逻辑都在源码中

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    //初始化beanName
    String beanName = this.transformedBeanName(name);
    //从缓存中加载bean,也就是从singletonObjects容器中获取
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    //如果缓存中存在bean
    if (sharedInstance != null && args == null) {
        //检查日志的trace
        if (this.logger.isTraceEnabled()) {
            //判断bean是否在创建,如果是则将信息加入到logger中
            if (this.isSingletonCurrentlyInCreation(beanName)) {
                this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
            } else {
                this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
		//将从缓存中获取到的bean进行实例化
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {//这是singletonObjects容器中没有对应的bean
        
        //此处进行循环依赖的检查,判断bean是否进行prototype类型的创建,如果是则抛出循环依赖异常,
        //Spring解决循环依赖需要bean是单例
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
		//加载父工厂,因为ingletonObjects容器中获取不到bean,所以到父工厂中获取
        BeanFactory parentBeanFactory = this.getParentBeanFactory();
        //判断父工厂是否为null以及判断配置文件是否包含bean所对应的属性,如果不包含就到parentBeanFacotory中加载bean
        if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
            String nameToLookup = this.originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }
            if (args != null) {
                return parentBeanFactory.getBean(nameToLookup, args);
            }
            if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            return parentBeanFactory.getBean(nameToLookup);
        }
        if (!typeCheckOnly) {
            this.markBeanAsCreated(beanName);
        }
        try {
            //获取bean的属性
            RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            this.checkMergedBeanDefinition(mbd, beanName, args);
            //判断当前bean是否依赖其它bean,如果依赖则先初始化依赖的这个bean
            String[] dependsOn = mbd.getDependsOn();
            String[] var11;
            if (dependsOn != null) {
                var11 = dependsOn;
                int var12 = dependsOn.length;

                for(int var13 = 0; var13 < var12; ++var13) {
                    String dep = var11[var13];
                    if (this.isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
					//注册一个当前bean依赖的其它bean,依赖的其它bean注册到dependenciesForBeanMap容器中
                    this.registerDependentBean(dep, beanName);

                    try {
                        this.getBean(dep);
                    } catch (NoSuchBeanDefinitionException var24) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
                    }
                }
            }
			//判断bean的类型(Singleton、Prototype、Scope),然后进行初始化
            if (mbd.isSingleton()) {
                sharedInstance = this.getSingleton(beanName, () -> {
                    try {
                        //创建bean方法
                        return this.createBean(beanName, mbd, args);
                    } catch (BeansException var5) {
                        this.destroySingleton(beanName);
                        throw var5;
                    }
                });
                bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                var11 = null;
                Object prototypeInstance;
                try {
                    this.beforePrototypeCreation(beanName);
                    prototypeInstance = this.createBean(beanName, mbd, args);
                } finally {
                    this.afterPrototypeCreation(beanName);
                }

                bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
                String scopeName = mbd.getScope();
                Scope scope = (Scope)this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        this.beforePrototypeCreation(beanName);

                        Object var4;
                        try {
                            var4 = this.createBean(beanName, mbd, args);
                        } finally {
                            this.afterPrototypeCreation(beanName);
                        }

                        return var4;
                    });
                    bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                } catch (IllegalStateException var23) {
                    throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var23);
                }
            }
        } catch (BeansException var26) {
            this.cleanupAfterBeanCreationFailure(beanName);
            throw var26;
        }
    }
	//检查所需类型是否与bean实例的类型是否匹配。
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            } else {
                return convertedBean;
            }
        } catch (TypeMismatchException var25) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);
            }

            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    } else {
        return bean;
    }
}

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    //存放单例bean的容器
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    //存放需要提前引用的bean的容器
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
    //存放依赖bean的容器
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap(64);
    

    
        @Nullable
    public Object getSingleton(String beanName) {
        return this.getSingleton(beanName, true);
    }

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        //将需要提前引用的bean存放到容器中
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }
}

总结

  • 各种面试题总说Spring解决循环依赖是依靠三级缓存,现在看了源码知道了三级缓存其实就是三个容器:singletonObjects 、earlySingletonObjects 、dependenciesForBeanMap 。

  • 整体流程总结:

    • 从singletonObjects 中加载bean,如果获取不到则将bean通过put方法放入earlySingletonObjects 中。

    • 如果获取到bean则将获取到的bean进行实例化

    • 进行循环依赖检查

    • singletonObjects 没有数据则到parentBeanFactory中获取

    • 获取bean的属性

    • 检查属性中是否依赖其它bean,如果依赖则先初始化依赖的bean

    • 最后根据不同的类型创建bean的实例

按照这个逻辑慢慢读,我懂了,你呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值