spring循环依赖

什么是循环依赖

循环依赖指bean之间相互依赖,但是注意只能是set注入属性类型(单例)的循环依赖能够被spring解决,如果是在构造函数中则会抛出异常BeanCurrentlyInCreationException

什么是三级缓存

	/** 一级缓存 这个就是我们大名鼎鼎的单例缓存池 用于保存我们所有的单实例bean */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 三级缓存 该map用户缓存 key为 beanName  value 为ObjectFactory(包装为早期对象) */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** 二级缓存 ,用户缓存我们的key为beanName value是我们的早期对象(对象属性还没有来得及进行赋值) */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

所谓的三级缓存就是这三个Map,分别存放不同形态的bean(2、3可能一样的),一级缓存存放的已经完成初始化的bean。三级缓存存放的是早期暴露的包装过的工厂。如果没有特殊处理, 那该工厂将会返回一个未完成初始化的bean。二级缓存存放的也是早期对象,但是不是包装的工厂对象,里面的对象属性还未进行赋值。

Spring如何利用三级缓存解决循环依赖问题

bean的实例化流程概述

在这里插入图片描述

该方法中调用preInstantiateSingletons()方法,实例化单例。过程如下

  1. 获取我们容器中所有的bean名称
  2. 合并bean定义
  3. 判断是否为工厂bean,调用getBean方法
  4. 进入到真正获取bean的逻辑中,doGetBean()
  5. 首先会进行第一次的从缓存中获取bean,getSingleton(beanName)。该方法下面再进行详解
  6. 如果没拿到,会进行一次判断,是否为正在创建的原型bean。如果是,则抛出BeanCurrentlyInCreationException。spring只能解决setter注入的循环依赖,而不能解决构造器的
  7. 随后进行父工厂的逻辑处理,一般只有spring整合spring mvc的时候才会出现子父容器。
  8. 经过之后的一些判断处理,来到创建单例bean的逻辑中,这里再次尝试从缓存中获取,只是参数出现变化,比起上面的第一次,这次多了一个lambda表达式
  9. 最终会在lambda中createBean进入到doCreateBean方法,进行bean的实例化。createInstance方法,这里是会调用无参或者有参构造。
  10. 实例化完成之后,会进行早期暴露的条件中,而允许早期暴露的条件有:单例、allowCircularReferences(默认true)和是否处于正在创建中isSingletonCurrentlyInCreation(这个后面细讲)
  11. 允许早期暴露的话,会将这个bean包装为一个singleFactory对象,并提供一个可以返回该bean的方法。
  12. 进入属性填充阶段,也就是产生spring能解决的循环依赖的地方populateBean方法。该方法比较复杂,简单理解就是这里会完成该bean的所有属性注入。那么当遇到对象属性时,会调用doGetBean,重新走刚刚的步骤。直到该对象属性也要进行属性赋值的时候。发现他依赖于刚刚第一次创建的bean,调用doGetBean方法,这里就能在第一次从缓存中获取对象拿到早期暴露的bean对象。然后该属性对象就完成了bean的整个创建流程,方法弹栈。回到第一个bean的属性填充,这里就能拿到属性对象,进而解决循环依赖的问题。

进入源码再过一遍

AbstractApplicationContext
    refresh()
    	finishBeanFactoryInitialization(beanFactory);  //实例化bean
		 preInstantiateSingletons()
             
DefaultListableBeanFactory
             
            public void preInstantiateSingletons() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Pre-instantiating singletons in " + this);
		}

		//获取我们容器中所有bean定义的名称
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		//循环我们所有的bean定义名称
		for (String beanName : beanNames) {
			//合并我们的bean定义
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			/**
			 * 根据bean定义判断是不是抽象的&& 不是单例的 &&不是懒加载的
			 */
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//是不是工厂bean
				if (isFactoryBean(beanName)) {
					//是的话 给beanName+前缀&符号
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						//调用真正的getBean的流程
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {//非工厂Bean 就是普通的bean
					getBean(beanName);
				}
			}
		}
 		//该方法这只截取一般,后半部分放在下面
进入getBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		/**
		 * 在这里 传入进来的name 可能是 别名, 也有可能是工厂bean的name,所以在这里需要转换
		 */
		final String beanName = transformedBeanName(name);
		Object bean;

		//尝试去缓存中获取对象
		Object sharedInstance = getSingleton(beanName);

		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			/**
			 * /*
			 * 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
			 * sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
			 * bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
			 * 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
			 */
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else {
			/**
			 * spring 只能解决单例对象的setter 注入的循环依赖,不能解决构造器注入
			 */
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			/**
			 * 方法参数 typeCheckOnly ,是用来判断调用 #getBean(...) 方法时,表示是否为仅仅进行类型检查获取 Bean 对象
			 * 如果不是仅仅做类型检查,而是创建 Bean 对象,则需要调用 #markBeanAsCreated(String beanName) 方法,进行记录
			 */
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
				//创建单例bean
				if (mbd.isSingleton()) {
					//把beanName 和一个singletonFactory 并且传入一个回调对象用于回调
					sharedInstance = getSingleton(beanName, () -> {
						try {
							//进入创建bean的逻辑
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							//创建bean的过程中发生异常,需要销毁关于当前bean的所有信息
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

		}
		return (T) bean;
	}

这里对doGetBean进行了阉割,只留下核心的部分。第一次创建bean的时候,从缓存中肯定是拿不到的,直接到48行,创建单例bean(原型已经被处理过了,这里我将这部分代码删掉了)。

进入createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		
		try {
			/**
			 * 该步骤是我们真正的创建我们的bean的实例对象的过程
			 */
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isDebugEnabled()) {
				logger.debug("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

该方法进行了一些解析判断,这里略去。重点是第9行,进入真正的实例化Bean。

进入doCreateBean真正实例化对象
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		//BeanWrapper 是对 Bean 的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装 bean 的属性描述器
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			//从没有完成的FactoryBean中移除
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化 该方法很复杂也很重要
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//从beanWrapper中获取我们的早期对象
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		/**
		 * 该对象进行判断是否能够暴露早期对象的条件
		 * 单实例
		 * this.allowCircularReferences 默认为true
		 * isSingletonCurrentlyInCreation(表示当前的bean对象正在创建singletonsCurrentlyInCreation包含当前正在创建的bean)
		 */
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		//上述条件满足,允许中期暴露对象
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//把我们的早期对象包装成一个singletonFactory对象 该对象提供了一个getObject方法,该方法内部调用getEarlyBeanReference方法
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//给我们的属性进行赋值(调用set方法进行赋值)
			populateBean(beanName, mbd, instanceWrapper);
			//进行对象初始化操作(在这里可能生成代理对象)
			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);
			}
		}

		//允许早期对象的引用
		if (earlySingletonExposure) {
			/**
			 * 去缓存中获取到我们的对象 由于传递的allowEarlyReferce 是false 要求只能在一级二级缓存中去获取
			 * 正常普通的bean(不存在循环依赖的bean) 创建的过程中,压根不会把三级缓存提升到二级缓存中
			 */

			Object earlySingletonReference = getSingleton(beanName, false);
			//能够获取到
			if (earlySingletonReference != null) {
				//经过后置处理的bean和早期的bean引用还相等的话(表示当前的bean没有被代理过)
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				//处理依赖的bean
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			//注册销毁的bean的销毁接口
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

此处第12行,会调用bean的构造函数进行实例化对象。其实到这里能发现,spring通过构造函数实例化对象,当构造函数中存在循环依赖的时候,无法通过三级缓存进行解决。因为都无法完成实例化,更别说早期暴露对象了,对象都莫得。

OK,这里从26行开始,进行早期暴露对象的逻辑。关键在于35行的代码

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

这里就将该bean和这个SingletonFactory绑定起来。可以看一下这个函数接口中的方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		//判读我们容器中是否有InstantiationAwareBeanPostProcessors类型的后置处理器
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			//获取我们所有的后置处理器
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				//判断我们的后置处理器是不是实现了SmartInstantiationAwareBeanPostProcessor接口
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					//进行强制转换
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					//挨个调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

在第16行返回的就是我们放入的bean实例,如果我们没有进行一些增强的话,那么if逻辑是不会进入的。也就是说,通常情况下,该方法返回的就是我们放入的bean。没有任何变化。只是我们将bean封装到这样一个工厂中去了。

属性填充populateBean

属性填充的代码逻辑有些复杂,这里直接进入到对象属性的赋值部分,此处会调用doGetBean去获取对象属性

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

		//BeanWrapper 是对 Bean 的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装 bean 的属性描述器
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			//从没有完成的FactoryBean中移除
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化 该方法很复杂也很重要
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//从beanWrapper中获取我们的早期对象
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		/**
		 * 该对象进行判断是否能够暴露早期对象的条件
		 * 单实例
		 * this.allowCircularReferences 默认为true
		 * isSingletonCurrentlyInCreation(表示当前的bean对象正在创建singletonsCurrentlyInCreation包含当前正在创建的bean)
		 */
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		//上述条件满足,允许中期暴露对象
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//把我们的早期对象包装成一个singletonFactory对象 该对象提供了一个getObject方法,该方法内部调用getEarlyBeanReference方法
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//给我们的属性进行赋值(调用set方法进行赋值)
			populateBean(beanName, mbd, instanceWrapper);
			//进行对象初始化操作(在这里可能生成代理对象)
			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);
			}
		}

		//允许早期对象的引用
		if (earlySingletonExposure) {
			/**
			 * 去缓存中获取到我们的对象 由于传递的allowEarlyReferce 是false 要求只能在一级二级缓存中去获取
			 * 正常普通的bean(不存在循环依赖的bean) 创建的过程中,压根不会把三级缓存提升到二级缓存中
			 */

			Object earlySingletonReference = getSingleton(beanName, false);
			//能够获取到
			if (earlySingletonReference != null) {
				//经过后置处理的bean和早期的bean引用还相等的话(表示当前的bean没有被代理过)
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				//处理依赖的bean
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

	
		return exposedObject;
	}

我们再把这段代码拿过来,还是一样的,这里为了方便说明,我们将第一个bean命名为X,第二个为Y。现在就是在为X的属性赋值,对X的对象属性Y进行获取。也就是当前doGetBean的beanName就是Y。这里第一次从缓存中获取肯定还是为null。

在这里插入图片描述

上面也说了过程同X一致,直到对Y的属性进行赋值的时候。对Y的X属性进行赋值,则会尝试去获取X。

在这里插入图片描述

猜一猜这里能不能在doGetBean中拿到X呢?或者说是尝试第一次送缓存中获取,能拿到X吗?

答案是能拿到,不然就一直循环下去了。这里我们再来看看他是如何拿到的

getSingleton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		/**
		 * 第一步:我们尝试去一级缓存(单例缓存池中去获取对象,一般情况从该map中获取的对象是直接可以使用的)
		 * IOC容器初始化加载单实例bean的时候第一次进来的时候 该map中一般返回空
		 */
		Object singletonObject = this.singletonObjects.get(beanName);
		/**
		 * 若在第一级缓存中没有获取到对象,并且singletonsCurrentlyInCreation这个list包含该beanName
		 * IOC容器初始化加载单实例bean的时候第一次进来的时候 该list中一般返回空,但是循环依赖的时候可以满足该条件
		 */
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				/**
				 * 尝试去二级缓存中获取对象(二级缓存中的对象是一个早期对象)
				 * 何为早期对象:就是bean刚刚调用了构造方法,还来不及给bean的属性进行赋值的对象
				 * 就是早期对象
				 */
				singletonObject = this.earlySingletonObjects.get(beanName);
				/**
				 * 二级缓存中也没有获取到对象,allowEarlyReference为true(参数是有上一个方法传递进来的true)
				 */
				if (singletonObject == null && allowEarlyReference) {
					/**
					 * 直接从三级缓存中获取 ObjectFactory对象 这个对接就是用来解决循环依赖的关键所在
					 * 在ioc后期的过程中,当bean调用了构造方法的时候,把早期对象包裹成一个ObjectFactory
					 * 暴露到三级缓存中
					 */
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//从三级缓存中获取到对象不为空
					if (singletonFactory != null) {
						/**
						 * 在这里通过暴露的ObjectFactory 包装对象中,通过调用他的getObject()来获取我们的早期对象
						 * 在这个环节中会调用到 getEarlyBeanReference()来进行后置处理
						 */
						singletonObject = singletonFactory.getObject();
						//把早期对象放置在二级缓存,
						this.earlySingletonObjects.put(beanName, singletonObject);
						//ObjectFactory 包装对象从三级缓存中删除掉
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

上面的步骤简单的概括一下,首先从一级缓存中拿,拿不到就去二级缓存拿,还是拿不到就去三级缓存中拿。ok拿到了就将他放到二级缓存中,并从三级缓存中剔除。

其实到这里循环依赖就已经解决,可以发现spring是通过早期对象暴露的方式+三级缓存,解决循环依赖的问题。

填坑

关于SingletonCurrentlyInCreation

/** 该集合用户缓存当前正在创建bean的名称 */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

它其实是DefaultSingletonBeanFactory中的一个属性。用于保存当前正在创建的bean。出现在我们进行是否能够早期暴露的条件中。

要能够进行早期暴露,要满足该bean正在进行创建过程。那么是在什么时候将bean添加到该集合中的呢?

是在第一次从单例池中获取bean实例的时候,肯定为null嘛,接下来就要对它进行创建,所以这里就进行了标记beforeSingletonCreation(beanName);,也就是调用createBean之前。

protected void beforeSingletonCreation(String beanName) {
		//若singletonsCurrentlyInCreation 没添加成功                                    添加到正在创建的集合中
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

为什么是三级缓存呢?两个缓存已经够解决循环依赖了

首先,刚刚流程走下来,我们发现,其实二级缓存并没有什么卵用。真的没用吗?我们回想刚刚的getSingleton方法,获取bean的过程,先从一级拿,然后二级最后三级。那么我们在三级缓存中拿的时候会去调用这个工厂的getRefference方法,里面包含着一块关于代理的逻辑。假设这里我们还有一个bean Z依赖于X,那么前面Y已经将X添加到二级缓存后,Z就直接能够从二级缓存中拿到,而不用去再走一遍三级缓存的中的代理逻辑。这是其一。

其二,两个缓存真的够解决循环依赖吗? 而且现在也感受不到三级缓存改成一个工厂的原因。我们不妨假设Y需要的是一个完成初始化的X。那么如果说我们三级缓存并不是一个工厂,那么这里保存的始终是bean的早期对象。没有自己生产bean的能力。关于两个缓存是否能够解决循环依赖的问题,网上大牛们也是各执一词,这里我就简单的提一下我认为合理的观点。

总结

最后总结一下:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring循环依赖指的是在Spring中,多个Bean之间存在相互依赖的情况。具体来说,当一个Bean A依赖于另一个Bean B,同时Bean B也依赖于Bean A时,就形成了循环依赖。这种情况下,Spring需要解决Bean的创建和依赖注入的顺序问题。 在Spring中,循环依赖问题是由于Bean的生命周期所引起的。Spring的Bean生命周期包括了Bean的实例化、属性注入、初始化以及销毁等过程。当出现循环依赖时,Spring会通过使用“提前暴露”的方式来解决这个问题。 具体来说,当Spring创建Bean A时,发现它依赖于Bean B,于是会创建一个A的半成品对象,并将其暂时放入一个缓存中。然后,Spring会继续创建Bean B,并将其注入到A的属性中。接着,Spring会继续完成B的创建,并将其放入缓存中。最后,Spring会将A的半成品对象交给B进行依赖注入,完成A的创建,并将其从缓存中移除。 需要注意的是,Spring循环依赖有一定的限制条件。例如,如果Bean A和Bean B都是单例模式,那么它们之间的循环依赖是无法解决的。因为单例模式下,Bean的创建和依赖注入是同时进行的,无法通过缓存来解决循环依赖。在这种情况下,程序员需要手动调整Bean的依赖关系或使用其他解决方案来避免循环依赖的问题。 综上所述,Spring循环依赖是指在Spring中多个Bean之间存在相互依赖的情况。Spring通过使用缓存和提前暴露的方式来解决循环依赖问题,但在某些情况下有一定的限制条件需要注意。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值