spring 源码探索--单例bean解决循环依赖问题

来源:互联网 发布:卖淘宝小号的网站 编辑:程序博客网 时间:2024/05/24 08:32

spring 中循环依赖问题:

ItemA 依赖ItemB,ItemB依赖ItemC,ItemC依赖ItemA,这就造成了循环依赖。
循环依赖有两种实现方式:构造函数,setter注入

单例模式

  • 构造函数
public ItemA(ItemB itemB){    this.itemB = itemB;}

这种情况造成的循环依赖在spring中是无法解决的,只能报BeanCurrentlyInCreationException
在spring中,使用类的构造的函数实例化bean之前,即singletonObject = singletonFactory.getObject();调用这个之前,会判断是否当前的bean是否正在创建,如果当前bean正在创建,则会报异常。如果不正在创建,则加入创建bean的池中进行标记。

  • setter注入

即通过getter/setter方法注入bean.
这种情况可以解决,通过当实例化完bean,还没完成初始化时,提前暴露出一个ObjectFactory,这个工厂正好返回的是刚刚完成实例化的bean.

暴露ObjectFactory工厂

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&                isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {    if (logger.isDebugEnabled()) {        logger.debug("Eagerly caching bean '" + beanName +                "' to allow for resolving potential circular references");    }    addSingletonFactory(beanName, new ObjectFactory<Object>() {        @Override        public Object getObject() throws BeansException {            return getEarlyBeanReference(beanName, mbd, bean);        }    });}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {        Assert.notNull(singletonFactory, "Singleton factory must not be null");        synchronized (this.singletonObjects) {            if (!this.singletonObjects.containsKey(beanName)) {                this.singletonFactories.put(beanName, singletonFactory);                this.earlySingletonObjects.remove(beanName);                this.registeredSingletons.add(beanName);            }        }}

首先我们需要先了解几个bean的缓存池的作用
1. singletonObjects :BeanName和创建bean实例之间的关系(注:不是最终返回的bean,可能是FatoryBean)
2. singletonFactores: BeanName和创建bean的工厂
3. earlySingletonObjects: BeanName和创建bean实例之间的关系,与1有所不同,bean实例还处于创建的过程中,可以通过getBean获取,用于检测循环引用。(ps:这个缓存池与2是互斥的)
4. registeredSingletons:用来保存所有已经注册的bean.

到了这里,已经暴露了正在创建中的bean的ObjectFactory。
接下来就来到了初始化bean,注入相关的依赖
populateBean(beanName, mbd, instanceWrapper);

在这里面会注入依赖的bean,当有循环引用出现,一定有一个终止的条件才能解决循环依赖,就像递归一样。
在最开始加载bean的时候,spring首先从缓存中读取bean.

protected Object getSingleton(String beanName, boolean allowEarlyReference) {        Object singletonObject = this.singletonObjects.get(beanName);        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {            synchronized (this.singletonObjects) {                singletonObject = this.earlySingletonObjects.get(beanName);                if (singletonObject == null && allowEarlyReference) {                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);                    if (singletonFactory != null) {                        singletonObject = singletonFactory.getObject();                        this.earlySingletonObjects.put(beanName, singletonObject);                        this.singletonFactories.remove(beanName);                    }                }            }        }        return (singletonObject != NULL_OBJECT ? singletonObject : null);}

如果能在这几个缓存池拿到循环依赖的bean,那么循环依赖就解决了。
A -> B -> C -> A
假如一开始加载A对象,现在假如到了创建A的依赖C这个地方,那A现在的状态是刚刚完成构造函数的实例化,准备进行完成注入其他bean。这个时候创建他的ObjectFactory也已经加入到了singletonFactores,C这个时候去注入A,通过上面的getSingleton方法即可拿到刚刚实例化完的A对象。最后回到A对象,A继续完成其他属性的注入,此时C引用的A已经不再是刚刚实例化完的A对象了。整个依赖完成。

假设在上面的getSingleton方法上没有得到bean A,那异常BeanCurrentlyInCreationException会在再次创建bean A之前发生。
有一个正在创建bean池,会记录当前创建中的bean。

protected void beforeSingletonCreation(String beanName) {        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {            throw new BeanCurrentlyInCreationException(beanName);        }}

原型模式

无法解决循环依赖,因为spring容器不缓存prototype作用域的bean.

0 0
原创粉丝点击