spring解决循环依赖,二级缓存的作用

首先bean是spring中对一个完整对象的定义,而对象是java中的一个定义。一个完成的bean肯定是一个对象,一个对象有可能不是一个完成的bean。

参考博客:https://www.jianshu.com/p/8bb67ca11831

什么是循环依赖

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
spring解决循环依赖,二级缓存的作用_第1张图片

循环依赖是怎么解决的

spring的三层缓存

一级缓存:
/** 保存所有的singletonBean的实例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

二级缓存:
/** 保存所有早期创建的Bean对象,这个Bean还没有完成依赖注入 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
三级缓存:
/** singletonBean的生产工厂*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

每层的作用

流程分析

spring解决循环依赖,二级缓存的作用_第2张图片

调用

public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果一级缓存中获取bean获取不到,并且对象正在创建中,则从二级缓存earlySingletonObjects中获取
		//isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中,
		// 也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或
		// 则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。)
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果还是获取不到且允许singletonFactories通过getObject()获取,
				// 就从三级缓存singletonFactory.getObject()(三级缓存)获取
				//allowEarlyReference是否允许从singletonFactories中通过getObject拿到对象
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//如果获取到了则从singletonFactories中移除,并放入earlySingletonObjects中,也就是从三级缓存移动到了二级缓存
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		//返回单例对象
		return singletonObject;
	}

执行createBean方法

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

		if (logger.isDebugEnabled()) {
			logger.debug("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			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);
		}
	}

执行docreateBean方法

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

		// Instantiate the bean.
		//BeanWrapper提供设置和获取属性值(单独或批量),获取属性描述符和查询属性以确定它们是可读还是可写的功能
		BeanWrapper instanceWrapper = null;
		//单例的情况下尝试从factoryBeanInstanceCache获取 instanceWrapper
		if (mbd.isSingleton()) {
			//map的remove方法返回值,则是移除的key对应的value
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//如果没有则需要自己创建
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		//如果不是NullBean,则将resolvedTargetType 属性设置为当前的WrappedClass
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		//    这边主要是寻找几个meta,@PostConstruct,@Autowire,@Value,@Resource,@PreDestory等
		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.
		//如果当前bean是单例,且支持循环依赖,且当前bean正在创建,通过往singletonFactories添加一个objectFactory,
		//这样后期如果有其他bean依赖c该bean 可以从singletonFactories获取到bean,getEarlyBeanReferene可以对返回的bean进行修改,这边目前除了可能会返回动态代理对象 其他的都是直接返回bean
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		//提前曝光bean
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//这里是解决循环依赖的关键,发生在createBeanInstance之后
			/*也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,
			虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),
			所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用*/
			// see :DefaultSingletonBeanRegistry.addSingletonFactory
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//对bean进行属性填充;其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean实例
			populateBean(beanName, mbd, instanceWrapper);
			//初始化bean, 处理 bean 初始化完成后的各种回调,例如init-method 配置,BeanPostProcessor接口
			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,尝试从缓存获取该bean(一般存放在singletonFactories对象通过
		// 调用getObject 把对象存入earlySingletonObjects),分别从singletonObjects和earlySingletonObjects获取对象
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			//如果获取到对象了
			if (earlySingletonReference != null) {
				//当exposedObject (初始化之后的bean等于原始的bean,说明不是proxy),则把缓存中的bean赋值给exposedObject
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				//检测该bean的dependon的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.
		//注册DisposableBean
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

执行createBeanInstance方法

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		//解析class
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		//如果beanclass不为空,且beanclass不是public 且没有权限访问构造函数和方法则抛出异常
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		//Supplier类似于factoryBean,然后从Supplier.get()的bean,并把bean包装成BeanWrapper,然后初始化BeanWrapper
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		// 1.如果存在工厂方法则使用工厂方法实例化bean对象
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
		// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
		//resolved: 构造函数或工厂方法是否已经解析过
		boolean resolved = false;
		// autowireNecessary: 是否需要自动注入(即是否需要解析构造函数参数)
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				//说明曾经解析过构造函数或者factoryMethod
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					// 2.1 如果resolvedConstructorOrFactoryMethod缓存不为空,则将resolved标记为已解析
					resolved = true;
					// 2.2 根据constructorArgumentsResolved判断是否需要自动注入
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		//如果已经解析过了则按照逻辑选择
		if (resolved) {
			// 3.如果已经解析过,则使用resolvedConstructorOrFactoryMethod缓存里解析好的构造函数方法
			if (autowireNecessary) {
				// 3.1 需要自动注入,则执行构造函数自动注入
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// 3.2 否则使用默认的构造函数进行bean的实例化
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		// 说明是第一次创建该bean   根据SmartInstantiationAwareBeanPostProcessor获取构造函数,
		// 目前看基本上都是空的实现,除了AutowiredAnnotationBeanPostProcessor
		// 4.应用后置处理器SmartInstantiationAwareBeanPostProcessor,拿到bean的候选构造函数
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		// 解析的构造器不为空 || 注入类型为构造函数自动注入 || bean定义中有构造器参数 || 传入参数不为空
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			//构造函数自动注入,开始生成实例
			// 5.如果ctors不为空 || mbd的注入方式为AUTOWIRE_CONSTRUCTOR || mdb定义了构造函数的参数值 || args不为空,则执行构造函数自动注入
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// No special handling: simply use no-arg constructor.
		// 使用默认构造器,采用普通的方式生成实例
		// 6.没有特殊处理,则使用默认的构造函数进行bean的实例化
		return instantiateBean(beanName, mbd);
	}

二级缓存存在的作用

spring解决循环依赖,二级缓存的作用_第3张图片

A放入三级缓存中是一个factory对象,是因为spring目前还无法判断,A对象在后续是否存在循环依赖,所以factory对象的目的在于,如果发生了循环依赖,则需要创建被增强的对象,而为什么又是被增强的对象呢,因为,我记得spring对bean的增强统一在后置处理中,但是由于被依赖,所以必须提前创建好被增强的对象,放入到二级缓存中。否则在程序运行中是代理对象A,而B拿到的对象却是普通对象A。
但是那跟放入二级缓存有啥关系呀,那是因为,如果不放入二级缓存中,那只能还是从三级缓存中获取,那么会再次触发aop增强:

doCreateBean方法中:
//提前曝光bean
if (earlySingletonExposure) {
	if (logger.isDebugEnabled()) {
		logger.debug("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	//这里是解决循环依赖的关键,发生在createBeanInstance之后
	/*也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,
	虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),
	所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用*/
	// see :DefaultSingletonBeanRegistry.addSingletonFactory
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

所以,到最后创建完整之后,加入到一级缓存中

所以综上所述,解决循环依赖的关键点就是第三级缓存的存在。

spring为什么不支持构造器循环依赖

因为A中构造器注入了B,那么A在关键的方法addSingletonFactory()之前就去初始化了B,导致三级缓存中根本没有A,所以会发生死循环,Spring发现之后就抛出异常了。至于Spring是如何发现异常的呢,本质上是根据Bean的状态给Bean进行mark,如果递归调用时发现bean当时正在创建中,那么久抛出循环依赖的异常即可

你可能感兴趣的:(spring,java,后端)