关于spring循环依赖的思考

spring主要处理的是属性注入的循环依赖,即beanA的属性中有beanB,beanB的属性中有beanA。

而其主要的解决方式则是在创建beanA但是还有没有对beanA进行赋值之前先将beanA的索引注册到容器中,而在beanA进行属性赋值时会引起beanB的创建操作,而在beanB的创建过程中需要进行属性赋值,而其获取beanA的属性值则是获取的beanA先暴露到容器的对象。

下面来详细描述一下上面那段解释,首先写一个循环依赖的例子:

@Component
public class CircleA {
	
	@Autowired
	public CircleB circleB ; 
	
	public void test() {
		System.out.println(circleB) ; 
	}
	
}

@Component
public class CircleB {
	
	@Autowired 
	public CircleA circleA ; 
	
	public void test() {
		System.out.println(circleA) ; 
	}

}

public class TestCircle {
	
	public static void main(String[] args) {
		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(new String[] {"classpath:spring-circle.xml"},false) ; 
		application.refresh();
		CircleA circleA = application.getBean(CircleA.class) ; 
		System.out.println(circleA) ; 
		circleA.test();  
		System.out.println("===========================") ; 
		CircleB circleB = application.getBean(CircleB.class) ; 
		System.out.println(circleB) ; 
		circleB.test();  
		System.out.println(circleA.circleB == circleB) ; 
		System.out.println(circleB.circleA == circleA) ; 
	}

}

/*================输出=============
com.test.spring.circle.CircleA@1efee8e7
com.test.spring.circle.CircleB@1ee807c6
===========================
com.test.spring.circle.CircleB@1ee807c6
com.test.spring.circle.CircleA@1efee8e7
true
true
*/



上面的代码清单描述了一个简单的循环依赖情况,CircleA中有CircleB的属性,而CircleB中有CircleA中的属性。

下面这个图是从容器中获取circleA的调用栈,可以看到它是先调用了DefaultListableBeanFactory#getBean方法来获取circleA,circleA在进行创建过程中调用了populateBean方法来进行属性的注入,而在注入过程中由于依赖circleB,所以又调用了getBean方法获取circleB,而circleB在创建过程中由于依赖CircleA而再次调用getBean方法获取circleA,但是这次circleA没有继续进行创建操作,因为之前circleA已经将其对象索引通过ObjectFactory注册到容器中了,所以这次getBean的方法最终调用的getSingleton的方法与之前的getSingleton方法有所不同,是173行的方法。

关于spring循环依赖的思考_第1张图片

上面的调用栈中可以看到前面两次调用对应getSingleton()都是230行的,最后一次是173行的,下面来分析一下这两个getSIngleton方法先看230行对应的getSingleton()方法。

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			if (this.singletonsCurrentlyInDestruction) {
				... throws
			}
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			...
			try {
                //#####获取bean实例的方法
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				...
			}
			finally {
				...
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
                //注册到singletonObjects中
				addSingleton(beanName, singletonObject);
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
}

上面的代码清单很清单,先从singletonObjects这个map中找对应的实例,找不到则利用ObjectFactory获取对应的实例,并将获取的实例注册到singletonObjects中。

对于上面的例子来说circleA和circleB在刚开始在容器都没有数据,则都会利用singletonFactory进行创建。而这个singletonFactory最终调用了DefaultListableBeanFactory的createBean方法来进行bean的创建。

上面的例子中它在创建circleA的过程中会在circleA实例化后先将circleA的实例利用ObjectFacotry注册到容器中。其具体操作是在AbstractAutowireCapableBeanFactory的doCreateBean进行操作的。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
		throws BeanCreationException {

	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
        //实例化circleA
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
	Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
	mbd.resolvedTargetType = beanType;

	...

	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		//将circleA的实例注册到DefaultSingletonBeanRegistry中
		addSingletonFactory(beanName, new ObjectFactory() {
			@Override
			public Object getObject() throws BeansException {
				return getEarlyBeanReference(beanName, mbd, bean);
			}
		});
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
        //属性注册,并且对circleB进行了创建
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
	}
	catch (Throwable ex) {
		...
	}

	...

	return exposedObject;
} 
  

上面这段代码描述了在实例化circleA之后,在对circleA进行属性注册(实例化circleB)之前进行了一项操作,即将circleA以ObjectFactory的形式注册到了DefaultSingletonBeanRegistry中。最终circleB在属性注入的时候则不需要进行circleA的创建,而是从ObjectFactory中直接获取circleA的实例。其具体获取的方式则是在173行的getSingleton方法中。

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) {
                    //circleA注册进入的beanFactory,最终获取的是刚开始创建的circleA的实例
                    //再进行包装的对象
					singletonObject = singletonFactory.getObject();
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

上面的代码可以看到其获取实例的方式是先从singletonObjects中获取对应的bean,如果没有获取则是从earlySingletonObjects中获取bean

 

 

 

你可能感兴趣的:(spring学习笔记,spring)