SpringIOC容器解决循环依赖源码分析

636 阅读5分钟

spring的ioc来解决循环依赖的问题,从AbstractBeanFactory#getBean方法来进行源码分析,spring的解决循环依赖的原理,可以从三个本地缓存Map集合进行调解,本篇文章打算从循环依赖的定义来解释,在结合源码进行分析。

什么是循环依赖

最简单的例子,spring的循环依赖,就是类A依赖类B,类B依赖类A,他们之间就行成了循环依赖。这是最简答例子,依据此方案就可以依赖3个类相互依赖可能导致死循环的状况。看代码实现:

`

@Servcie
Class A {
    @Autowired
    private B b;
}

@Service
Class B {
    @Autowired
    private A a;
}

IOC容器去加载bean的时候,按照顺序去加载,会优先加载beanA然后会注入beanB,发现beanB没被实例,接下来会加载beanB然后注入beanA,这时候发现beanA没被实例。导致整个过程形成死循环,程序会一直加载,最终导致内存溢出。spring解决方案,采用三级缓存的实现方案,在容器加载beanB的时候,发现beanB依赖beanA,容器会在加载beanA放入到早期缓存,并把这个早期beanA注入到beanB中,beanB完成实例。beanA也就可以完成实例化。

三级缓存介绍

`

/** Cache of singleton objects: bean name to bean instance. */
//最终缓存
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. */
//存放bean工厂对象,用于解决循环依赖
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

源码分析

我们直接从AbstractBeanFactory#doGetBean方法开始分析。 `

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	//对bean进行check ,如果bean已经被实例就直接返回bean
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
	 //。。。中间省略细节

	// Create bean instance.
	//根据bean的作用域去分析
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
			    //这是创建bean的方法
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				// Explicitly remove instance from singleton cache: It might have been put there
				// eagerly by the creation process, to allow for circular reference resolution.
				// Also remove any beans that received a temporary reference to the bean.
				destroySingleton(beanName);
				throw ex;
			}
		});
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}

	else if (mbd.isPrototype()) {
		// It's a prototype -> create a new instance.
		Object prototypeInstance = null;
		try {
			beforePrototypeCreation(beanName);
			prototypeInstance = createBean(beanName, mbd, args);
		}
		finally {
			afterPrototypeCreation(beanName);
		}
		bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
	}

	else {
		String scopeName = mbd.getScope();
		final Scope scope = this.scopes.get(scopeName);
		if (scope == null) {
			throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
		}
		try {
			Object scopedInstance = scope.get(beanName, () -> {
				beforePrototypeCreation(beanName);
				try {
					return createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
			});
			bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
		}
		catch (IllegalStateException ex) {
			throw new BeanCreationException(beanName,
					"Scope '" + scopeName + "' is not active for the current thread; consider " +
					"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
					ex);
		}
	}
}
catch (BeansException ex) {
	cleanupAfterBeanCreationFailure(beanName);
	throw ex;
}
}

` 上面是获取bean的过程,先是从缓存中获取bean,如果没有会去创建bean

`

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //先从最终缓存获取实例
	Object singletonObject = this.singletonObjects.get(beanName);
	//判断beanName对应的bean是否正在创建中
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
		    //从早期缓存中获取
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
			    //获取相应的bean工厂
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					//将刚实例的bean放入早期工厂中
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

上面的源码中,doGetBean 所调用的方法 getSingleton(String)是一个空壳方法,其 主要逻辑在 getSingleton(String, boolean) 中。该方法逻辑比较简单,首先从 singletonObjects 缓存中获取 bean 实例。若未命中,再去 earlySingletonObjects 缓存中获取原始 bean 实例。如果仍未命中,则从 singletonFactory 缓存中获取 ObjectFactory 对象,然后再调用 getObject 方法获取原始 bean 实例的应用, 也就是早期引用。获取成功后,将该实例放入 earlySingletonObjects 缓存中,并将 ObjectFactory 对象从 singletonFactories 移除。看完这个方法,我们再来看看 getSingleton(String, ObjectFactory) 方法,这个方法也是在 doGetBean 中被调用的。下面我们继续往下跟踪doCreateBean方法 `

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

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
	    //将bean实例化,并且包裹BeanWrapper对象中
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	if (beanType != NullBean.class) {
		mbd.resolvedTargetType = beanType;
	}

	// Allow post-processors to modify the merged bean definition.
	synchronized (mbd.postProcessingLock) {
		if (!mbd.postProcessed) {
			try {
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Post-processing of merged bean definition failed", ex);
			}
			mbd.postProcessed = true;
		}
	}

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		//将bean工厂对象加入到singletonFactories对象早期bean工厂
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
	        //注入属性bean
		populateBean(beanName, mbd, instanceWrapper);
		//执行一些初始化参数例如BeanNameAware
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {
		if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
			throw (BeanCreationException) ex;
		}
		else {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
		}
	}

` 在创建bean的过程分为三个部分,①、创建原始bean实例createBeanInstance,②、添加原始对象工厂对象到singletonFactories,③、注入属性bean。下面这张图是摘自别人博客

总结

本篇文章是对整个ioc如何解决循环依赖的,其实本质就是ioc容器加载的核心部分,相应的bean生命周期的核心也能在本篇透析出来。以上就是ioc的讲解,本人能力有限,大家相互进步哟。