天天看点

spring 单例的循环依赖

现象

  • 两个类都是spring的单例类,两个类里面有一个成员变量,变量都是对方。
@Component
public class BeanA
{
	@Resource
	private BeanB beanB;
	
}

@Component
class BeanB
{
	@Resource
	private BeanA beanA;
	
}
           

这个问题不是什么复杂的问题。正常思路是这样的。

BeanA a = new BeanA();
BeanB b = new BeanB();

a.setBeanB(b);
b.setBeanA(a);
           

spring 创建对象

spring的思路是这样子的,这个就出现了循环依赖的问题

public static BeanA createA() {

	BeanA beanA = new BeanA();
	BeanB b = createB();
	beanA.setBeanB(b);
	return beanA;
}

public static BeanB createB() {
	BeanB beanB = new BeanB();
	BeanA a = createA();
	beanB.setBeanA(a);
	return beanB;
}
           

spring的理念是,只要你创建一个对象,那么这个对象中的需要自动注入的属性就要即时注入,如果没有就创建这个属性,或者报错。

  • spring的解决方式(引入缓存)伪代码
private static Map<String,Object> cacheObjects = new HashMap<>();

	public static BeanA createA() {
		// 先从缓存中获取
		BeanA beanA = (BeanA) cacheObjects.get("beanA");
		if (beanA != null){
			return beanA;
		}
		beanA = new BeanA();
		cacheObjects.put("beanA",beanA);
		BeanB b = createB();
		beanA.setBeanB(b);
		return beanA;
	}

	public static BeanB createB() {
		// 先从缓存中获取
		BeanB beanB = (BeanB) cacheObjects.get("beanB");
		if (beanB != null){
			return beanB;
		}
		beanB = new BeanB();
		cacheObjects.put("beanB",beanB);
		BeanA a = createA();
		beanB.setBeanA(a);
		return beanB;
	}
           

源码解读

流程图

spring 单例的循环依赖
  • 先尝试从缓存中拿取实例
// 从缓存中拿取实例
		Object sharedInstance = getSingleton(beanName);
           

缓存容器

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

从缓存中先尝试获取

....
	Object singletonObject = null;
		// 从三级缓存中获取实例
	ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
	if (singletonFactory != null) {
		singletonObject = singletonFactory.getObject();
	}

	return singletonObject;
		....
           

如果对象不存在创建一个对象

// 创建实例
	instanceWrapper = createBeanInstance(beanName, mbd, args);
           

创建对象之后加入缓存,注意这个对象是一个空的对象。

之后来进行属性注入

// 获取有@AutoWired 注解的字段和方法
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			// 进行设置值
			metadata.inject(bean, beanName, pvs);
		}
           
// 获取依赖注入的值
	value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
           

如果它是一个对象类型的数据,最终触发getBean操作

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
		throws BeansException {

	return beanFactory.getBean(beanName);
}