spring源码分析之bean循环依赖

前言

spring的ioc容器帮助我们解决了复杂对象之前的创建问题,我们需要什么对象,只要是被spring管理的bean都可以直接向spring获取改对象,但是当A对象里面的属性是B对象 ,而B对象里面包含属性A对象,这种情况就叫做循环依赖,spring是怎么处理的呢?本文就一起来探讨一下spring是如何解决循环依赖的,以及能解决什么类型的循环依赖。

一、循环依赖是什么?

循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A
依赖于B,B依赖于C,C⼜依赖于A。是对象的相互依赖关系。跟循环调用不同,循环调⽤其实就是⼀个死循环,除⾮有终结条件

在这里插入图片描述
在spring中bean会先实例化,然后再注入属性,注入属性大致分两种

  1. 构造函数注入
  2. set方法注入
    其中,构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决
    属性循环依赖时,spring采⽤的是提前暴露对象的⽅法。也就是常说的采用三级缓存!

二、循环依赖处理机制

在Spring中只有设置为单例的通过setXxx或者 @Autowired⽅法才能解决循环依赖。其他的都会抛出BeanCurrentlyInCreationException异常。

prototype 原型 bean循环依赖(⽆法解决)

AbstractBeanFactory.doGetBean()⽅法:

// 如果是 Prototype 并开启循环依赖 报错
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
 Object curVal = this.prototypesCurrentlyInCreation.get();
 return (curVal != null &&
 (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>)
curVal).contains(beanName))));
}

在获取bean之前如果这个原型bean正在被创建则直接抛出异常。原型bean在创建之前会进⾏标记
这个beanName正在被创建,等创建结束之后会删除标记

try {
 //创建原型bean之前添加标记
 beforePrototypeCreation(beanName);
 //创建原型bean
 prototypeInstance = createBean(beanName, mbd, args);
}
finally {
 //创建原型bean之后删除标记
 afterPrototypeCreation(beanName);
}

单例 bean set注入循环依赖解决过程

流程图
在这里插入图片描述
Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器。
通过xml注入TestBean和Itbean来分析循环依赖的调用过程

测试代码

IocTest

	/**
	 *  Ioc 容器源码分析基础案例
	 */
	@Test
	public void testIoC() {
		// ApplicationContext是容器的高级接口,BeanFacotry(顶级容器/根容器,规范了/定义了容器的基础行为)
		// Spring应用上下文,官方称之为 IoC容器(错误的认识:容器就是map而已;准确来说,map是ioc容器的一个成员,
		// 叫做单例池, singletonObjects,容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程)

		/**
		 * Ioc容器创建管理Bean对象的,Spring Bean是有生命周期的
		 * 构造器执行、初始化方法执行、Bean后置处理器的before/after方法、:AbstractApplicationContext#refresh#finishBeanFactoryInitialization
		 * Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
		 * Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors
		 */

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		TestBean testBean = applicationContext.getBean(TestBean.class);
		System.out.println(testBean);
	}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="
	    http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
">

	<!--循环依赖问题-->
	<bean id="testBean" class="com.my.test.TestBean">
		<property name="ItBean" ref="itBean"/>
		<property name="name" value="aa"/>
	</bean>
	<bean id="itBean" class="com.my.test.ItBean">
		<property name="TestBean" ref="testBean"/>
	</bean>


<!--	<bean id="myBeanFactoryPostProcessor" class="MyBeanFactoryPostProcessor"/>-->
<!--	<bean id="myBeanPostProcessor" class="MyBeanPostProcessor"/>-->


	<!--<bean id="testBean" class="TestBean">
	</bean>-->


<!--	&lt;!&ndash;aop配置&ndash;&gt;-->
<!--	&lt;!&ndash;横切逻辑&ndash;&gt;-->
<!--	<bean id="logUtils" class="LogUtils">-->
<!--	</bean>-->

<!--	<aop:config>-->
<!--		<aop:aspect ref="logUtils">-->
<!--			<aop:before method="beforeMethod" pointcut="execution(public void TestBean.print())"/>-->
<!--		</aop:aspect>-->
<!--	</aop:config>-->


</beans>

TestBean

package com.my.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @Author
 * @create 2019/12/3 11:46
 */
public class TestBean implements InitializingBean, ApplicationContextAware {

	private ItBean itBean;
	private String name;

	public void setItBean(ItBean itBean) {
		this.itBean = itBean;
	}

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * 构造函数
	 */
	public TestBean(){

		System.out.println("TestBean 构造器...");
	}


	/**
	 * InitializingBean 接口实现
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("TestBean afterPropertiesSet...");
	}

	public void print() {
		System.out.println("print方法业务逻辑执行");
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println("setApplicationContext....");
	}
}

ItBean

package com.my.test;

/**
 * @author
 */
public class ItBean {

	private TestBean testBean;

	public void setTestBean(TestBean testBean) {
		this.testBean = testBean;
	}

	/**
	 * 构造函数
	 */
	public ItBean(){
		System.out.println("ItBean 构造器...");
	}
}

开始初始化TestBean

调用AbstractBeanFactory.doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)

// 从ioc容器中获取  如果为空则是该类第一次初始化
		Object sharedInstance = getSingleton(beanName);

DefaultSingletonBeanRegistry.getSingleton(String beanName, boolean allowEarlyReference)

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		// 先从一级缓存单例池中获取
		Object singletonObject = this.singletonObjects.get(beanName);
		// 单例池中还没有 并且当前类正在初始化
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		// 一级缓存没有  从二级缓存中获取
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
			// 二级缓存没有 加锁三级缓存对象
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					// 从一级缓存中拿
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
					// 一级缓存中没有 从二级缓存中拿
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
						// 二级缓存没有 从三级缓存中拿
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
							// 三级缓存有 将对象从三级缓存移除 添加到到二级缓存中
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

创建之前先调用DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory ) 看一下是否在单例池中是否该对象 没有在创建

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 + "'");
				}
				// 验证完成要真正创建对象。先标识bean 正在被创建 因为spring bean 创建过程复杂 步骤多 需要标识
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 传进来的调用 lamda表达式使用
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

然后调用AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)开始创建

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

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		// 拿到RootBeanDefinition
		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 {
			//真正创建bean的方法
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("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);
		}
	}

将实例化好的TestBean放入三级缓存中
在这里插入图片描述

// 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");
			}
			// 先添加到三级缓存中
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}


protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
		// 当前bean不在一级缓存
			if (!this.singletonObjects.containsKey(beanName)) {
			// 添加到三级缓存
				this.singletonFactories.put(beanName, singletonFactory);
				// 删除二级缓存
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

注入TestBean属性时需要 初始化itBean

开始注入属性 itBean 创建bean 回到调用AbstractBeanFactory.doGetBean

AbstractBeanFactory.doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
在这里插入图片描述
C.将实例化好的 ItBean 放入三级缓存中
在这里插入图片描述
**D. ItBean 注入属性类TestBean 又回到调用AbstractBeanFactory.doGetBean **
在这里插入图片描述
从DefaultSingletonBeanRegistry.getSingleton(String beanName, boolean allowEarlyReference) 方法三级缓存中拿到TestBean 并将其从三缓存中移除 放入二级缓存中 这个时候ItBean 还在三级缓存哦
在这里插入图片描述
在这里插入图片描述
ItBean已经注入好属性TsetBean
在这里插入图片描述

itBean初始化完成

调用DefaultSingletonBeanRegistry.addSingleton将ItBean放入一级缓存中

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
		// 一级缓存添加
			this.singletonObjects.put(beanName, singletonObject);
			// 三级缓存删除
			this.singletonFactories.remove(beanName);
			// 二级缓存删除
			this.earlySingletonObjects.remove(beanName);
			// 注册单例名称set集合
			this.registeredSingletons.add(beanName);
		}
	}

在这里插入图片描述

完成TestBean初始化 放入单例池

在这里插入图片描述

总结

spring ioc容器对单例非懒加载的bean进行初始化时都会先将bean实例化后放入三级缓存singletonFactories中,然后进行属性注入。属性注入能直接注入,就会放入一级缓存singletonObjects,如果注入的是类,则会立即初始化需要注入的类。当需要注入的类实例化后,会先将实例化的类放入三级缓存中,再将最开始的类从三级缓存中移除到二级缓存。当类的所有属性都注入后就会将其添加到单例池中,并从三级和二级缓存中删除。

文章源码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起风了 收衣服

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值