Spring 循环依赖解决思路完整源码分析

Spring 循环依赖问题解决思路

循环依赖问题,直接代码问题如下

@Service("clientServices")
public class ClientServices {
	@Autowired
	private UserServices userServices;

	public ClientServices() {
		System.out.println("ClientServices Constructed");
	}
}
@Service("userServices")
public class UserServices {
	@Autowired
	private ClientServices clientServices;

	public UserServices() {
		System.out.println("UserServices Constructed");
	}
}

分析: ClientServices中依赖于UserServices作为其类的属性,UserServices也依赖于ClientServices作为其类的属性,如何解决这种循环依赖并且能够顺利的在IoC容器中实例化对应的bean呢?

解决关键点: 在首次创建其中一个bean A时,如果发现存在循环依赖,并且Spring开启循环依赖,则记录其中一个bean A正在创建中(还未完成bean A的生命周期)、此时调用createBean去实例化需要依赖的另外一个bean B。在第二个bean B被实例化时,也会发现自己依赖的属性A也还没有创建(单例池中取不到A),故而去实例化要依赖的bean A,于是回到了最初实例化bean A的起点,但是这一次创建,Spring发现A依赖的属性B正在被创建,则直接会从earlySingletonObjects获取并返回即取到正在创建中但是还未完成完整bean生命周期的bean B、于是bean A成功获取到其所需要的属性 B,顺利完全其生命周期,成为一个Spring bean;之后,bean B依赖的属性A可以从singletonObjects(单例池)中取到,在完成其完整bean生命周期后,也成为一个Spring bean。从而得到解决。

看不懂没关系,关键看下面的源码分析。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		// 验证bean的名字是否非法
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		/* getSingleton方法解析:
		* 这里是第一次调用getSingleton方法,下面spring还会调用一次
		* 但是两次调用的方法非同一个方法(方法重载)
		* 第一次getSingleton(beanName)是循环依赖最重要的方法
		* 具体内容:
		* 1、spring去单例池获取这个bean,单例池是一个Map
		* 2、如果对象被创建了则直接从Map中获取并返回
		* 理解:doGetBean方法不仅仅是用来第一次获取bean,而是创建bean和getBean方法共用的一个方法
		* 循环引用需要在创建bean的时候去获取被引用的类,而被引用的类此时还没有被创建,
		* 则会调用creatBean来创建这个bean,创建这个bean时则会检查是否已经被实例化
		* 对象:类被实例化后
		* bean:经过一系列bean生命周期后,放入单例池中的对象
		* 回到循环引用,首先spring扫描到一个需要被实例化的类A,于是创建a:A a = new A();
		* new A的过程中Spring会去调用getBean("a");此时,get结果肯定为空。
		* 原因:(并非因为getBean是从容器中获取,所以为空)
		* 第一次调用getSingleton(beanName)方法后,spring判断这个类没有创建
		* 然后Spring第二次调用getSingleton(重载方法),在里面记录了一下自己已经开始实例这个类了。
		* 面试:说明spring实例化一个对象底层用的是反射;spring实例化一个对象的过程非常复杂,需要推断构造方法、单例原型、懒加载等.
		* 对象在完成spring的bean生命周期的过程中,会去判断IoC容器是否允许循环引用(spring默认支持循环引用)
		* 如果允许循环依赖,spring把这个对象的beanDefinition暂存到Map中(并非单例池的singletonObjects)
		* 另外还有存放临时对象的earlySingletonObjects。
		* 3 Map:
		*	singletonObjects(存放单例bean):缓存创建好的bean,方便Coder getBean
		* 	singletonFactories(存放临时对象(没有 完整Spring-Bean生命周期的对象))
		* 	earlySingletonObjects(同上)
		* 后面两个Map支撑循环引用。
		* 当进行对象 a的属性填充时,发现a依赖了B类,然后spring判断这个B类到底有没有bean在IoC容器中
		* 这里的判断是从第一个map:singletonObjects中 getBean。
		* 假设没有,则spring调用createBean,于是重复A的过程,在创建B b时,调用getBean("b")
		* 此时get结果必然为null,而此时第一次调用完getSingleton后进而调用第二次getSingleton
		* 第二次调用时会在set集合中记录B b正在创建(此时,set集合中已有至少2条记录a和b正在被创建)
		* 如果为空,则B b = new B();接着完善b的bean生命周期,同样会判断是否允许循环依赖,允许则放到第二个map:singletonFactories
		* 此时singletonFactories中已经存在a和b,紧接着对b的属性进行填充时发觉需要依赖A,于是就去第一个Map中去寻找a(此时a还只是对象非bean)
		* 故而getBean("a")为null,所以 b判定a还没有创建,故而去创建了a,事件线又回到了起点(循环)
		* 但是,这次会判断a是否等于null,如果为空,则进而判断a是否正在创建中(set集合记录了a)
		* 如果a正在被创建(被set记录了),则直接从第二个map:earlySingletonObjects中取出a并返回,所以这一次就不等于空了
		* 于是乎B就可以自动注入a了,但a还只是一个对象,a这个对象依赖的b还没有注入,当b对象注入完成a后,把b的bean生命周期走完,存到IoC容器中
		* 此时,返回到a注入b的地方,得到的返回对象也是一个bean(b),a故而能够注入b了,进而a也放入到IoC容器中进行管理。
		* */
		// 第一次get不到
		// sharedInstance 为null
		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 + "'");
				}
			}
			// 处理FacotryBean的情况
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 此处针对原型bean??
			// 判断这个原型bean是不是在创建过程中
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			// 检查bean是否存在于父级IoC容器中
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				// 当没找到这个bean时,获取父级容器中beanFactory利用beanName调用父级beanFactory的doGetBean方法
				// beanName:符合系统规范的bean名,name指最原始的名
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
			// 如果不仅仅是类型检查,则利用beanName去标记当前正在创建的bean
			// 当仅仅是进行类型检查时,则不会记录当前正在创建的bean
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				// 获取合并的beanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 检查beanDefinition是否为抽象类
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// 获取@DependsOn注解的依赖
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					// 优先创建依赖的类,如果此时发生循环依赖,则会报错
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 将依赖关系注册到集合中
						registerDependentBean(dep, beanName);
						try {
							// 递归调用getBean方法获取当前所依赖的bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				// 单例bean
				if (mbd.isSingleton()) {
					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;
						}
					});
					// 处理FactoryBean的情况
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				// 当beanDefinition是原型(多例)对象时,直接调用createBean方法创建实例
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						// 原型bean的循环依赖检测(记录正在创建ing)
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					// 处理FactoryBean的情况
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					// 获取该bean的生命周期范围@Scope,在refesh()方法中的postProcessBeanFactory方法进行自定义生命周期注册
					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);
							}
						});
						// 处理FactoryBean的情况
						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;
			}
		}

		// Check if required type matches the type of the actual bean instance.
		// 最后一步检查: 检查指定类型与实际得到的bean类型是否存在出入,如果是,则尝试进行转换
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值