spring源码解读-4.把创建的bean丢到容器中

这里呢,说丢到容器中,其实单例bean才有探讨价值;非单例的每次获取是重新进行create的;
大家应该都听过三级缓存。循环依赖这些概念。spring把bean丢在容器中,其实就是和三级缓存进行交互,现在呢就来揭开三级缓存的面纱。以及看看Spring中如何解决循环依赖的;但是今天的主题不探究为什么这样解决哈。我也不建议你现在思考为什么,因为你还不知道他是啥就研究为什么不是自讨苦吃吗?切记别想啊,现在就是去看是什么,而不是为什么!ok?
在这里插入图片描述

下面分几个场景来讲:

场景1:如果简简单单的创建一个bean,没有循环依赖的情况;

先说结论:其实咱们只需要用到一级缓存;逻辑也很简单,就是创建bean,然后创建完成把bean放到一级缓存中;没那么多花里胡哨的;这样就够了。但是其实这里面三级缓存也被放了一个带有bean引用的工厂,但是没用到,创建完成就删除了;这时候在三级缓存的存在就是个没用的废物;

先按照场景1的思路看:
getBean到doGetBean发现没有去createBean然后调用doCreateBean;这个链路都熟悉了不?
去doGetBean里面找到下面这一段;这里就是创建逻辑开始的地方;咱们就从这里开始看:
路标1:ObjectFactory的getObject方法里面调用createBean
这里只是创建了一个ObjectFactory作为getSingleton的参数,并没有真正调用createBean;
下面进去getSingleton方法;

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							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;
							}
						}
					});

路标2:singletonFactory.getObject()

1.可以看到这里面调用了上面传入的singletonFactory的getObject方法;然后间接的去调用了createBean,然后拿到创建的bean的值;

2.这里面创建bean的值拿到之后调用了
addSingleton(beanName, singletonObject);
这里面就是创建完成对象之后加入到一级缓存的逻辑。
看路标3咱们进去看看

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "'beanName' 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 the 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<Exception>();
				}
				try {
					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 != NULL_OBJECT ? singletonObject : null);
		}
	}

路标3:直接看注释吧

任何单例bean创建成功都会走到这个逻辑;

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			//加入到一级
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			//删除三级
			this.singletonFactories.remove(beanName);
			//删除二级
			this.earlySingletonObjects.remove(beanName);
			//标记该单例已经注册
			this.registeredSingletons.add(beanName);
		}
	}

场景一整体逻辑看完了。但是好像没看到另外两个缓存什么事是不是。确实在场景1的情况下另外两个缓存存在的意义不大。三级缓存存在了一霎那,但是也是个没用到的废物。
那一霎那在哪里呢。其实就是在创建bean的逻辑中;带着疑问看场景2的时候你自然就能看到了。

场景2:如果存在循环依赖的情况下

在这里插入图片描述

也先说结论:这里三个缓存都用到了;过程是这样的

在这里插入图片描述

这里解决循环依赖的关键就是提前把A暴露给B使用了。什么叫提前呢?就是说没初始化完成就给B了。

这里呢大家要先熟记住,Spring在出现循环依赖的时候的整个处理流程。一定要知道他是怎么处理了之后,你才有必要去问他为什么要这样做。不然你都不知道这个东西是什么你就去研究为什么的话,那不就本末倒置了么;没记住的看到这里赶紧翻上去再看一遍;记住了的话咱们继续往下看;

下面咱们先不研究为什么,因为本篇主题是看源码。咱们根据上面的流程去看代码。而不是为什么这样设计。为什么这样设计的思路大家可以看我另外一篇文章 《Spring三级缓存解决循环依赖必要性研讨》。现在先别去啊,先看代码。

下面看场景2源码:
先按照整流程来讲。已经看过的代码我就不打开了。不然篇幅太长读者也累;
下面你凭本事找这几个路子的源码,你也可以debugger来跟;
第1步: 创建A 进入doCreateBean方法,然后里面开始实例化A;

第2步: 实例化A完后后有下面这一段

路标21:addSingletonFactory
场景1结束的疑问到这里就可以解决了!
addSingletonFactory这里呢就是往三级缓存添加一个对象工厂的地方;也就是添加了一个ObjectFactory,但是这里并没有调用这个getEarlyBeanReference哦。只是封装进去而已并没有调用。

	if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

然后咱们先看看工厂里面getEarlyBeanReference里面做了什么:
你看不懂它做了什么是不。其实没关系,后面文章会讲。这里只要记住就行了。它就是对这个要创建的bean进行代理。然后把代理过的对象进行返回;执行完addSingletonFactory A加到了三级缓存中
路标22:getEarlyBeanReference

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
					if (exposedObject == null) {
						return exposedObject;
					}
				}
			}
		}
		return exposedObject;
	}

第4步:初始化A 你自己找到populateBean(beanName, mbd, instanceWrapper);这里面的逻辑前面你也看过了。就是给A的属性赋值。然后
第5步:从容器获取获取B
代码不贴了。你只要知道这里面会调用getBean去找B就行了;
第6步: 找B发现没找到B。去通过调用doCreateBean创建B
第7,8步: 创建B时候实例化成功,然后同样会addSingletonFactory 把B放三级缓存
第9步: 到初始化B的逻辑发现需要A那么就去找A.
第10步: 调用doGetBean(A)去找A的时候,会执行这里Object sharedInstance = getSingleton(beanName);
好,之前每次路过这里都是返回空,因为之前看到这里都是返回空;现在这次这里面不会返回空了;咱们进去看看;

这里就是从三级缓存取值的逻辑。就是挨个找呗,一级找不到找二级,二级找不到找三级;如果三级找到了,就调用singletonFactory.getObject();这时候就会触发上面的那个getEarlyBeanReference进行代理然后把代理对象放到二级缓存,删除三级缓存

路标:22

		protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}

第11,12,13步:
B拿到A的早期引用,再往后,B创建完成;
完成后:B的创建逻辑会,调用addSingleton(String beanName, Object singletonObject)
移入一级缓存
第14,15,16步:
B完成后,B返回给A,A也完成了。A移入一级缓存addSingleton(String beanName, Object singletonObject) ,
整个流程结束

就这么个逻辑。

好了写到这里整个bean如何丢到容器中的源代码就都走过一遍了。能get到多少就看你自己的了;

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值