这里呢,说丢到容器中,其实单例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到多少就看你自己的了;