spring中的循环依赖

Posted 我爱看明朝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring中的循环依赖相关的知识,希望对你有一定的参考价值。

spring中的循环依赖

循环依赖的场景

1.构造器的循环依赖
2.field属性的循环依赖

如果两个对象是构造器的循环依赖,这中是没有什么办法解决,当A构造器依赖B,B构造器依赖A,无法提前实例化,以及缓存,因此无法处理。
spring对bean的创建是分三个步骤:1.通过构造器new出对象;2.设置属性;3.执行设置的初始化函数。field属性的循环依赖时,我们可以完成
构造器的执行,得到对象的引用地址,传给依赖的属性,后面再对这个对象设置相关的属性。就处理了field属性的循环依赖。

filed循环依赖示例

@service
public class ServiceA 

    @autowired
    private ServiceB serviceb;



@service
public class ServiceB

    @autowired
    private ServiceA servicea;



@service
public class Demo 

    @Autowired
    private ServiceA servicea;

    @autowired
    private ServiceB serviceb;


当spring创建Demo时,先执行默认无参构造器,创建对象Demo,然后设置属性servicea,serviceb,当创建serviceA时,先执行构造器,获得引用地址,加入缓存,填充A的属性再创建serviceB,
执行B的构造器,填充属性,从缓存中查到A的引用地址,填充,返回B的引用,给A; A,B完成创建。

spring在处理field的循环依赖使用了三级缓存方案。

源码分析

protected <T> T doGetBean()
    // Eagerly check singleton cache for manually registered singletons.
    // 从缓存中查询bean
	Object sharedInstance = getSingleton(beanName);



public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry 

	/** Cache of singleton objects: bean name --> bean instance */
    // 一级缓存: 完整的bean
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

	/** Cache of early singleton objects: bean name --> bean instance */
    // 二级缓存: 只执行了构造器的bean
	private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

	/** Cache of singleton factories: bean name --> ObjectFactory */
    // 三级缓存:只执行了构造器的ObjectFactory
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

    	protected Object getSingleton(String beanName, boolean allowEarlyReference) 
        // 一级缓存查询,是否存在
		Object singletonObject = this.singletonObjects.get(beanName);
        //如果不存在,并且bean正在创建中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 
			synchronized (this.singletonObjects) 
                // 从二级缓存查询
				singletonObject = this.earlySingletonObjects.get(beanName);
                //二级缓存不存在以及允许从三级缓存中查询ObjectFactory
				if (singletonObject == null && allowEarlyReference) 
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) 
                        //三级缓存查询到了ObjectFactory,通过ObjectFactory获取到引用地址
						singletonObject = singletonFactory.getObject();
                        //从三级缓存获取到了,加入到二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
                        //在从三级缓存中移除
						this.singletonFactories.remove(beanName);
					
				
			
		
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	

    //加入一级缓存存储ObjectFactory,此时只是执行了构造器,还未填充属性,获得了引用地址,
	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的创建,加入到一级缓存
	protected void addSingleton(String beanName, Object singletonObject) 
		synchronized (this.singletonObjects) 
            // 加入一级缓存,并且从二,三级缓存移除
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		
	


总结

1.spring可以处理field属性的循环依赖,不能处理构造器的循环依赖
2.spring通过三级缓存解决了循环依赖问题
3.使用三级缓存解决循环依赖的基础是:spring对bean的创建分为三个步骤: 执行构造器、填充属性、执行初始化方法

参考

Spring中的循环依赖解决详解

Spring-bean的循环依赖以及解决方式

spring中bean创建过程中的扩展点

以上是关于spring中的循环依赖的主要内容,如果未能解决你的问题,请参考以下文章

spring中的循环依赖

spring中的循环依赖

Spring中的循环依赖及解决

Spring是如何解决循环依赖的?

spring学习笔记循环依赖(待完善)

Spring — 循环依赖