Spring循环依赖原理分析

Posted 赵晓东-Nastu

tags:

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

一、思维导图

二、什么是循环依赖

从这个图中可以看出,当有2个对象互相依赖的时候,在创建的时候会存在一个环形的调用,导致创建对象失败。

所以:循环依赖是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了一个环形调用。

三、如何解决循环依赖

通过三级缓存来解决循环依赖的问题

/** Cache of singleton objects: bean name --> bean instance */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

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

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

具体的步骤是什么样子的?

首先走Refresh()方法,开始实例化

		//初始化剩下的单实例(从这里开始进行实例化了)
				// Instantiate all remaining (non-lazy-init) singletons.
		finishBeanFactoryInitialization(beanFactory);

将这个方法走进去就进入到了下面 

		//实例化剩下的所有的非懒加载的单例对象
		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();

通过beanName获取 

				//如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例
					getBean(beanName);
	@Override
	public Object getBean(String name) throws BeansException {
		//此方法是实际获取bean的方法,也是触发依赖注入的方法
		return doGetBean(name, null, null, false);
	}

接下来我需要判断,获取对象,从容器里面获取,容器里面保存了三级缓存

	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;
		//接下来就是获取bean的对象
		// 尝试通过bean名称获取目标bean对象,比如这里的A对象
		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);

接下来我们走到getSingleton方法中

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//尝试从缓存中获取成品的目标对象,如果存在,则直接返回
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果缓存中不存在目标对象,则判断当前对象是否已经处于创建过程中,
		//第一次尝试获取A对象的实例之后,就会将A对象标记为正在创建中,因而最后再尝试获取A对象的时候这里的if就会为true
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					//这里的singletonFactories是一个map ,其key是bean的名称,而值是一个ObjectFactory类型的
					//对象,这里对于A和B而言,调用getObject()方法返回的就是A和B对象的实例,无论是否是半成品
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//获取目标对象的实例
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

刚开始的时候,if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 这个判断是false,所以直接返回的是null。

因为还没有被创建,所以返回空值,容器里面没有,所以接下来就是去创建了。

			//这里的目标对象都是单例的
				// Create bean instance.
				if (mbd.isSingleton()) {
					//这里就尝试创建目标对象。第二个参数传的就是一个ObjectFactory类型的对象,这里是
					//使用Java8的lamada表达式写的,只要上面的getSingleton()方法返回值为空,则会调用这里的
					//getSingleton方法
					sharedInstance = getSingleton(beanName, () -> {
						try {
							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);
				}

接下来我们走进getSingleton方法,从singletonFactory.getObject()获取对象,这个也就是传进来的lambda表达式createBean()

 

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					//从单例工厂中获取对象
					singletonObject = singletonFactory.getObject();
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		//实例化当前获取的bean对象,比如A对象和B对象都是在这里实例化的
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//没有就创建实例
		if (instanceWrapper == null) {
			//根据执行bean使用对应的策略创建新的实例,如:工厂方法,构造函数主动注入,简单初始化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

所以从现在开始就开始进行对象的实例化操作了,然后走到createBeanInstance方法,创建实例。

此时完成了半成品,实例化结束了,接下来就是填充属性了。

			//如果支持,这里就会将当前生产的半成品的bean放到singletonFactories中,
			//这个singletonFactories 就是前面第一个getSingleton()方法中所使用的singletonFactories属性,也就是说
			//这里就是封装半成品的bean的地方,而这里的getEarlyBeanReference()本质上
			//是直接将放入的第三个参数,也就是目标bean直接返回
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		//使用singletonObjects进行加锁,保证线程安全
		synchronized (this.singletonObjects) {
			//如果单例对象的告诉缓存【bean名称-bean实例】没有beanName对象
			if (!this.singletonObjects.containsKey(beanName)) {
				//将beanName , singletonFactory放到单例工厂的缓存[bean名称-objectFactory]
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				//将beanName添加已注册的单例集中
				this.registeredSingletons.add(beanName);
			}
		}
	}

从源代码中可以看出,spring将创建好的对象实例化放入到了singletonFactories中

接下来填充属性

			//在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了
			//就会递归的调用getBean()方法尝试获取目标bean
			populateBean(beanName, mbd, instanceWrapper);

走进去

		if (pvs != null) {
			//应用给定的属性值,解决任何在这个bean工厂运行时其他bean的引用
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
				String propertyName = pv.getName();
				Object originalValue = pv.getValue();
				Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
				Object convertedValue = resolvedValue;

然后到valueResolver.resolveValueIfNecessary(pv, originalValue);

	@Nullable
	public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
		// We must check each value to see whether it requires a runtime reference
		// to another bean to be resolved.
		if (value instanceof RuntimeBeanReference) {
			RuntimeBeanReference ref = (RuntimeBeanReference) value;
			return resolveReference(argName, ref);

点击进resolveReference

	@Nullable
	private Object resolveReference(Object argName, RuntimeBeanReference ref) {
		try {
			Object bean;
			String refName = ref.getBeanName();
			refName = String.valueOf(doEvaluate(refName));
			if (ref.isToParent()) {
				if (this.beanFactory.getParentBeanFactory() == null) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Can't resolve reference to bean '" + refName +
									"' in parent factory: no parent factory available");
				}
				bean = this.beanFactory.getParentBeanFactory().getBean(refName);
			}
			else {
					@Nullable
	private Object resolveReference(Object argName, RuntimeBeanReference ref) {
		try {
			Object bean;
			String refName = ref.getBeanName();
			refName = String.valueOf(doEvaluate(refName));
			if (ref.isToParent()) {
				if (this.beanFactory.getParentBeanFactory() == null) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Can't resolve reference to bean '" + refName +
									"' in parent factory: no parent factory available");
				}
				bean = this.beanFactory.getParentBeanFactory().getBean(refName);
			}
			else {
				bean = this.beanFactory.getBean(refName);

走到

bean = this.beanFactory.getBean(refName);

接下来又就到了

	@Override
	public Object getBean(String name) throws BeansException {
		//此方法是实际获取bean的方法,也是触发依赖注入的方法
		return doGetBean(name, null, null, false);
	}

开始递归循环。。。。然后都创建完实例并且存放到singletonFactories中,然后现在执行populateBean装配属性,然后userService,发现有一个属性是IndexService。

因此再次调用doGetBean创建userService实例,但是执行到getSingleton查询缓存的时候,从SingletonFactories三级缓存中查询到了userService实例(早起引用,未完成属性装配),此时直接返回userService,不用执行后续的流程创建userService了,那么IndexService就完成了属性装配,此时是一个完成的对象放入到了一级缓存singletonObjects中,

IndexService创建完了,则userService自然完成了属性装配,也创建完成放入一级缓存singletonObjects中

Spring三级缓存的应用完美解决了循环依赖的问题。

总结成图片:

 

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

Spring依赖注入和循环依赖问题分析

Spring依赖注入和循环依赖问题分析

Spring 循环依赖原理源码的探究和总结以及三级缓存的详解一万字

Spring循环依赖那些事儿(含Spring详细流程图)

Spring源码分析系列-循环依赖和三级缓存

Spring源码分析系列-循环依赖和三级缓存