spring循环依赖问题

	spring在DefaultSingletonBeanRegistry类中有以下几种缓存池:
	/** Cache of singleton objects: bean name to bean instance. */
	//singletonObjects:key存bean name,value存bean实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

/** Names of beans that are currently in creation. */
//singletonsCurrentlyInCreation存正在创建的bean名称
private final Set<String> singletonsCurrentlyInCreation =
		Collections.newSetFromMap(new ConcurrentHashMap<>(16));

/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions =
		Collections.newSetFromMap(new ConcurrentHashMap<>(16));
类DefaultSingletonBeanRegistry:
/**
	 * Callback before singleton creation.
	 * 在单例bean创建之前尝试回调
	 * <p>The default implementation register the singleton as currently in creation.
	 * 将单例bean注册为正在创建中的默认实现
	 * @param beanName the name of the singleton about to be created
	 * 参数为将要创建的bean名称
	 * @see #isSingletonCurrentlyInCreation
	 */
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

比如当A、B两个service相互依赖的时候:

@Service
public class ServiceAImpl implements ServiceA {
    private ServiceB serviceB;

    public ServiceAImpl(ServiceB serviceB) {
        this.serviceB = serviceB;
    }


    public String print() {
        return "service a print ";
    }
}

@Service
public class ServiceBImpl implements ServiceB {

    private final ServiceA serviceA;

    public ServiceBImpl(ServiceA serviceA) {
        this.serviceA = serviceA;
    }

    public String print() {
        return serviceA.print() + "service b print ";
    }
}

将工程启动,当spring创建bean时候,比如首先创建A:
在这里插入图片描述

可以看到首先将beanname serviceAImpl放到了singletonsCurrentlyInCreation,而由于serviceAImpl依赖了B,这时spring尝试初始化serviceBImpl,又将serviceBImpl放到了singletonsCurrentlyInCreation,又发现serviceBImpl依赖了serviceAImpl,因此又会尝试初始化serviceAImpl;再次来到beforeSingletonCreation方法:
在这里插入图片描述

注意这里Set singletonsCurrentlyInCreation里面已经包括了serviceAImpl和serviceBImpl,再次执行将导致!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)两个条件同时满足,直接导致了抛出异常throw new BeanCurrentlyInCreationException(beanName);

看一下BeanCurrentlyInCreationException
在这里插入图片描述

提示Requested bean is currently in creation: Is there an unresolvable circular reference?
说明spring确实检查到了循环依赖,并且没有办法处理,只能抛出异常

如果将其中一个bean改成使用setter注入方式:


@Service
public class ServiceAImpl implements ServiceA {

    private  ServiceB serviceB;

    public String print() {
        return " service a print ";
    }

    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

再次执行:
在这里插入图片描述

首先将A将入到singletonsCurrentlyInCreation,然后往下走,在getSingleton方法中,serviceAImpl添加到了到了earlySingletonObjects中,也就是所谓的提前暴露。

在这里插入图片描述
等到再次回到beforeSingletonCreation时,准备创建B,这时发现singletonsCurrentlyInCreation里面已经空了,而我们在registeredSingletons里面发现了ServiceAImpl的踪影:

在这里插入图片描述

说明当用setter方法注入的时候实际上会用默认无参构造函数将A实例化,而A持有的对象B将延后初始化,等到单例B真正被初始化后,才将B的实例设置到A中。

如果将B改成setter注入也是一样的结果。

结论:
如果两个bean之间有循环依赖,并且都是用构造器方式注入时,由于spring要使用默认构造函数实例化bean,会将两个bean都放到待创建set后然后抛异常。
而只要有至少一个bean初始化方式为setter方式时,就可以使用无参构造函数先将bean初始化,等到所依赖的bean被构造出来后再执行set,也就解决了循环依赖的问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章