前置文章:
doCreateBean之处理@Autowired以及@Value标签
doCreateBean完整源码如下:
1 | java复制代码protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) |
接上文分析到的位置,接下来执行:
1 | java复制代码// 向容器中缓存单例模式的Bean对象,以防循环引用 |
之后会来到
1 | java复制代码// 这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用 |
进入到addSingletonFactory:
1 | java复制代码protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { |
消除此Bean在二级缓存里的缓存信息,将其包装成singletonFactory实例往三级缓存里添加
这里有一个重点就是Spring解决循环依赖的真相就在这一段源码中:在这里beanFactory被put进了
singletonFactories
,此时的bean只是完成了初始化构造的bean,还没有进行set或者注解注入的bean,是bean的一个中间状态,但是已经能被人认出来了,所以Spring此时将这个对象提前曝光出来让大家认识、使用。
回到doCreateBean,进入到getEarlyBeanReference
1 | java复制代码protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { |
注意这个方法并不是在doCreateBean的
1 | java复制代码addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); |
这一行执行的,这里只是将getEarlyBeanReference注册进去,实际执行的地方是前面尝试从缓存里获取bean的地方,即AbstractBeanFactory的doCreateBean方法里。
回到doCreateBean,此时获取到了bean,并且只在三级缓存里面保存。
之后会执行
1 | java复制代码populateBean(beanName, mbd, instanceWrapper); |
来将bean的属性真正注入到里面,然后再调用initializeBean进行彻底的初始化
1 | java复制代码// Initialize the bean instance. |
之后判断该bean是否允许提前暴露,
1 | java复制代码if (earlySingletonExposure) { |
if 里面调用了getSingleton方法,进入该方法:
1 | java复制代码@Nullable |
和之前提到的是同一个方法,由于这时bean已经被放到三级缓存里了,所以会被从三级缓存里取出
1 | java复制代码singletonObject = singletonFactory.getObject(); |
获取到bean实例之后会将其从三级缓存里移除
1 | java复制代码this.singletonFactories.remove(beanName); |
回到doCreateBean,
1 | java复制代码Object earlySingletonReference = getSingleton(beanName, false); |
执行完毕之后再判断一下
1 | java复制代码if (exposedObject == bean) { |
exposedObject
由于之前调用了initializeBean
方法,所以有可能会被赋值为全新的对象,一旦被赋值了全新的对象之后if里面是false,进入到前面的initializeBean
方法里
重点关注applyBeanPostProcessorsAfterInitialization
方法,进入到方法里:
重点关注实现了postProcessAfterInitialization方法的AbstractAutoProxyCreator类
1 | java复制代码@Override |
该方法尝试从缓存里获取bean实例并返回,即如果先前加工过的话就返回bean实例,确保加工过的bean实例和先前是同一个。
回到doCreateBean,
1 | java复制代码if (exposedObject == bean) { |
如果不是同一个bean,则有可能经过initializeBean
之后没有返回同样的bean实例,之所以会出现这个问题是因为postProcessor也是供用户使用的,用户可能在自定义逻辑里修改了bean实例,用户的行为对于系统来说是无法预测的。
不一样的话就会检查有没有别的bean依赖于这个bean,如果存在则直接报错,因为既然执行到这里其他bean实例就已经执行过了populate方法将该bean的实例设置上了,然而设置上了之后却又创建出了该bean的新实例,于是就不满足单例。
通过验证之后会注册销毁时候的回调逻辑
1 | java复制代码registerDisposableBeanIfNecessary(beanName, bean, mbd); |
本文转载自: 掘金