spring bean 和 对象
Spring Bean的生命周期指的是从一个普通的Java类变成Bean的过程。
要理解bean的生命周期首先记住两个概念spring bean和对象。
1.spring bean是受spring容器管理的对象,可能经过了完整的spring bean生命周期。
为什么是可能?难道还有bean是没有经过bean生命周期的?
答案是有的,最终存在spring容器当中;一个bean一定是个对象。
2.对象是任何符合java语法规则实例化出来的对象,但是一个对象并不一定是spring bean。
所谓的bean的生命周期就是磁盘上的类通过spring扫描,然后实例化,跟着初始化,继而放到容器当中的过程。
bean的生命周期的步骤
通过图来了解一下spring bean的生命周期
找到beanDefinition,并放入beanDefinitionMap。
遍历beanDefinitionMap中的beanDefinition。开启bean的生命周期即实例化和初始化以及销毁。
上图就是spring容器初始化bean的大概过程。
用一个例子来证明上面的过程。
@Component
public class X {
@Autowired
Y y;
public X(){
System.out.println("X create");
}
}
@Component
public class Y {
@Autowired
X x;
public Y(){
System.out.println("Y create");
}
}
@Component
public class Z implements ApplicationContextAware {
@Autowired
X x;//注入X
//构造方法
public Z(){
System.out.println("Z create");
}
//生命周期初始化回调方法
@PostConstruct
public void zinit(){
System.out.println("call z lifecycle init callback");
}
//ApplicationContextAware 回调方法
@Override
public void setApplicationContext(ApplicationContext ac) {
System.out.println("call aware callback");
}
}
来看看Z的生命周期,会和上面的17个步骤一一对应,文字总结一下:
1:实例化ApplicationContext的对象。
2:调用BeanDefinitionRegistry工厂后置处理器完成扫描BeanDefinition。
3:循环解析扫描出来的类信息。
4:实例化一个BeanDefinition对象来存储解析出来的信息。
5:把实例化好的beanDefinition对象put到beanDefinitionMap当中缓存起来,以便后面实例化bean。
6:调用BeanFactoryPostProcessor工厂后置处理器。
7:当然spring还会干很多事情,比如国际化,比如注册BeanPostProcessor等等,如果我们只关心如何实例化一个bean的话。
那么这一步就是spring调用finishBeanFactoryInitialization方法来实例化单例的bean,实例化之前spring要做验证,需要遍历所有扫描出来的类,依次判断这个bean是否Lazy,是否prototype,是否abstract等等。
8:如果验证完成spring在实例化一个bean之前需要推断构造方法,因为spring实例化对象是通过构造方法反射,故而需要知道用哪个构造方法。
9:推断完构造方法之后spring调用构造方法反射实例化一个对象;注意我这里说的是对象、对象、对象;这个时候对象已经实例化出来了,但是并不是一个完整的bean,最简单的体现是这个时候实例化出来的对象的属性是没有注入,所以不是一个完整的bean。再就是@PostConstruct方法也没有调用,再一次说明他不是一个完整的bean,这里我们只能说z是个对象。
10:spring处理合并后的beanDefinition。applyMergedBeanDefinitionPostProcessors方法就是用来处理合并后的beanDefinition对象。
spring是通过createBeanInstance(beanName, mbd, args);完成了推断构造方法和实例化的事情。
11:判断是否支持循环依赖,如果支持则提前把一个工厂对象存入singletonFactories,singletonFactories是1个map。
12:判断是否需要完成属性注入
13:如果需要完成属性注入,则开始注入属性
14:判断bean的类型回调Aware接口
15:调用生命周期回调方法
16:如果需要代理则完成代理
17:put到单例池——bean完成——存在spring容器当中
至此一个bean完成初始化,被put到单例池,也就是对应上面的17个步骤。这说明一个bean在spring容器当中被创建出来是有一个过程的,这个过程就是所谓的bean的生命周期,我们的循环依赖也是在这个生命周期内完成的。
由于bean的生命周期特别复杂本文只对涉及到循环依赖的步骤做分析,其他生命周期的步骤我会在后续博客中分析,可以继续关注本专栏。
我们知道spring的bean是在AbstractApplicationContext#finishBeanFactoryInitialization()方法完成的初始化,即循环依赖也在这个方法里面完成的。该方法里面调用了一个非常重要的方法 doGetBean的方法
doGetBean方法内容有点多,这个方法非常重要,不仅仅针对循环依赖,甚至整个spring bean生命周期中这个方法也有着举足轻重的地位,读者可以认真看看笔者的分析。
需要说明的是我为了更好的说清楚这个方法,我把代码放到文章里面进行分析;但是删除了一些无用的代码;比如日志的记录这些无关紧要的代码。 首先笔者把精简后的代码贴出来方便大家阅读,下面重点说这个doGetBean方法
AbstractBeanFactory#doGetBean源码
protected <T> T doGetBean(final String name,
@Nullable final Class<T> requiredType,
@Nullable final Object[] args,
boolean typeCheckOnly)
throws BeansException {
//读者可以简单的认为就是对beanName做一个校验特殊字符串的功能
//我会在下次更新博客的时候重点讨论这个方法
//transformedBeanName(name)这里的name就是bean的名字
//解析bean 如果以&开头 去掉& 如果是别名获取真正的名字
final String beanName = transformedBeanName(name);
//定义了一个对象,用来存将来返回出来的bean
Object bean;
//继续调用getSingleton(String, true)从缓存中获取实例
//true是参数allowEarlyReference 代表饥渴加载!
//deGetBean-1 返回 sharedInstance = null
Object sharedInstance = getSingleton(beanName);
//deGetBean-2 不进入判断
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else{
//deGetBean-3 如果是多例&&正在创建 抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}else{
//doGetBean-4 判断是单例
if (mbd.isSingleton()) {
//getSingleton(String beanName, ObjectFactory<?> singletonFactory)
//注意这个方法的2个参数
//1.String
//2.ObjectFactory
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
}
}
}
注意:上面的代码是我对doGetBean方法进行了删减的代码,只保留了和本文讨论的循环依赖有关的代码,完整版可以参考spring的源码org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
接着笔者对上述代码逐行来解释。
deGetBean-1
getSingleton(String)源码
Object sharedInstance = getSingleton(beanName);
跟进DefaultSingletonBeanRegistry#getSingleton(String, boolean)
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
//是否应创建早期引用 allowEarlyReference is true
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从1级缓存中获取是空
Object singletonObject = this.singletonObjects.get(beanName);
//1级缓存中该bean为空 且 只有当前 bean 正在创建才能去2级缓存拿
//第一次进入这个方法的时候,因为还没有开始创建所以直接进入else就返回了
if (singletonObject == null
&& isSingletonCurrentlyInCreation(beanName)) {
//从2级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
//如果2级缓存也是空
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
//为了防止并发 加锁后再次从1级缓存获取
singletonObject = this.singletonObjects.get(beanName);
//如果1级缓存仍然为空
if (singletonObject == null) {
//为了防止并发 加锁后再次从2级缓存获取
singletonObject =
this.earlySingletonObjects.get(beanName);
//如果2级缓存仍然为空
if (singletonObject == null) {
//3级缓存中获取的是一个ObjectFactory
ObjectFactory<?> singletonFactory =
this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用ObjectFactory的getObject方法获取对象
singletonObject = singletonFactory.getObject();
//放入2级缓存
this.earlySingletonObjects.put
(beanName, singletonObject);
//从3级缓存移除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
首先这行代码上有一句spring作者写的注释
Eagerly check singleton cache for manually registered singletons.
别小看这句spring作者写的javadoc背后的意义,其实这里有两重意思;
要搞清楚这两重意思,首先要知道当代码执行到这里的时候其实是spring在初始化的时候执行过来的;
既然spring在初始化的时候他肯定知道这个类X.java肯定没有在容器当中,为什么还需要去验证一下呢?
因为一个bean被put到单例池的渠道有很多;除了spring容器初始化—扫描类----实例化-----put到容器这条线之外还有很多方法可以把一个对象put到单例池;我这里只列举一种,其他的有机会再讨论,看下图 注意注释;
所以上面提到的这句注释的两重意思。
第一,判断spring当前正准备初始化的bean有没有提前被put到容器;即缓存里到底有没有这个bean对应的实例
既然这里用来做spring初始化的工作,为什么这个方法名叫做doGetBean呢?
讲道理应该叫做createBean啊才合理啊;有读者可能会说这个方法命名可能作者乱写的,请注意spring之所以经久不衰命名规范绝对是一个重要原因,作者是不会这么乱给方法命名的。
诚然有的读者会说讨论这个的意义不大,其实博主觉得讨论这个非常重要;之所这里叫做doGetBean的原因就是因为这个方法就是用来获取bean的,他主要的工作不仅仅服务于spring bean的初始化;
这个方法的作用不仅仅是为了spring 在初始化bean的过程中去判断一下这个bean是否被注册了这么简单;笔者认为这个方法最主要的作用是为了从容器中得到一个bean,也就是说当我们在spring代码中调用getBean(“a”)其背后的意义就是调用这个doGetBean。
总结一下 Object sharedInstance = getSingleton(beanName);
目前看来主要是用于在spring初始化bean的时候判断bean是否在容器当中;以及供程序员直接get某个bean。
注意笔者这里用了 目前这个词;因为getSingleton(beanName);这个方法代码比较多;他里面的逻辑是实现循环依赖最主要的代码,文章下面我会回过头再来讲这个方法的全部意义。
请注意我们当前代码的场景,当前代码是spring容器在初始化的时候,初始化X这个bean的场景。运行到了Object sharedInstance = getSingleton(beanName)。根据上面的分析,这个时候我的X Bean肯定没有被创建,所以这里返回sharedInstance = =null;
deGetBean-2
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
由于 sharedInstance = =null 故而不会进入这个if分支,那么什么时候不等于null呢?两种情况
1.在spring初始化完成后程序员调用getBean(“x”)的时候得到的sharedInstance 就不等于null;
2.循环依赖的时候第二次获取对象的时候这里也不等于空;比如X 依赖 Y;Y依赖X;spring做初始化第一次执行到这里的时候X 肯定等于null,然后接着往下执行,当执行到属性注入Y的时候,Y也会执行到这里,那么Y也是null,因为Y也没初始化,Y也会接着往下执行,当Y执行到属性注入的时候获取容器中获取X,也就是第二次执行获取X;这个时候X则不为空;
至于具体原因,接着往下看;
至于这个if分支里面的代码干了什么事情,本文不讨论,放到后面写factoryBean的时候讨论,现在你可以理解if分支里面就把sharedInstance 原原本本的返回出来就行;
doGetBean -3
else{
//deGetBean-3
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
不进if (sharedInstance != null && args == null)分支,则进入这个else分支;
判断当前初始化的bean----X 是不是正在创建原型bean集合当中当中?
spring源码当中关于这行代码有两行javadoc
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//如果我们正在创建这个实例我们大概在一个循环引用中。
一般情况下这里返回false,也就是不会进入if (isPrototypeCurrentlyInCreation(beanName))分支抛异常。
为什么说一般情况下呢?
首先这里是判断当前的类是不是正在创建的多例集合当中,即里面只会存多例。
一般情况下我们的类不是原型即多例,而是单例的。
大家都知道spring默认是单例。
所以返回false,再就是即使这个bean是原型,也很少会在这里就存在正在创建的原型集合当中。
因为不管单例还是原型,bean在创建的过程中会add到这个集合当中,但是创建完成之后就会从这个集合remove掉(关于这个文章后面有证明),原型情况第一次创建的时候会add到这个集合,但是不是在这里,而是在后面的创建过程中add,所以这里肯定不会存在,即使后面过程中add到这个集合了,但是创建完成之后也会remove掉,故而下一次实例化同一个原型bean(原型可以实例化无数次)的时候当代码执行到这里也不可能存在集合当中了;
除非循环依赖会在bean还没有在这个集合remove之前再次判断一次,才有可能会存在,故而我前面说了一般情况下这里都返回false。
那么单例情况我们已经说了一定返回false,原型情况只有循环依赖才会成立,但是只要是正常人就不会对原型对象做循环依赖的;即使你用原型做了循环依赖这里也抛异常(因为if成立,进入分支 throw exception)。
再一次说明原型不支持循环依赖(当然你非得用原型做循环依赖,其实有办法,以后文章说明,本文忽略);
画了一幅图说明上面的文字,因为这个集合非常重要,但是读者如果这里不理解也没关系,文章下面我还会结合代码分析一次;
重点来了:什么叫做正在创建的原型集合呢?
因为还有一个与之对应的叫做正在创建的单例集合。唯一的区别就是集合里面存的是单例和原型,故而我们统称正在创建的集合
doGetBean-4
else{
// 判断当前bean是否单例
if (mbd.isSingleton()) {
// getSingleton原本长这样
// getSingleton(String beanName, ObjectFactory<?> singletonFactory)
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
}
代码有点多,if (mbd.isSingleton())比较简单:判断当前bean是否单例,本文环境下是成立的。继而
//函数式接口
@FunctionalInterface
public interface ObjectFactory<T> {
//()->{ return createBean(beanName, mbd, args); } 相当于是实现方法
//即调用AbstractBeanFactory的createBean方法
//作为ObjectFactory接口getObject方法的实现
T getObject() throws BeansException;
}
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
这里第2次调用getSingleton(String beanName, ObjectFactory<?> singletonFactory)。
如果有印象上面也调用了1次getSingleton(String name),
这是方法重载,两个getSingleton方法并不是同一个方法,读者自己看参数就行。
为了区别我这这里叫做第二次调用getSingleton;上文的叫做第一次调用getSingleton;
第一次调用相当于从ioc容器中获取即缓存中获取对象
第二次调用相当于自己创建一个bean对象放入ioc容器
由于这里使用lamda表达式,有些读者看起来不是很理解;笔者改一下吧
ObjectFactory<?> singletonFactory = new ObjectFactory(){
public Object getObject(){
//其实这是个抽象类,不能实例化
//createBean是子类实现的,这里就不关心了
//你就理解这不是一个抽象类吧
AbstractBeanFactory abf = new AbstractBeanFactory();
//AbstractBeanFactory.createBean(beanName, mbd, args);
Object bean = abf.createBean(beanName, mbd, args);
return bean;
};
};
//传入 beanName 和 singletonFactory 对象
sharedInstance = getSingleton(beanName,singletonFactory);
当然第二次getSingleton就会把我们bean创建出来,换言之整个bean如何被初始化的都是在这个方法里面;
至此本文当中笔者例举出来的doGetBean方法的核心代码看起来解析完成了;
注意我说的是本文当中例举的doGetBean代码,前面我已经说了我删了很多和循环依赖无关的代码,实际spring源码当中这个方法的代码很多,以后文章介绍吧;
接下来就要研究第二次getSingleton方法的内容了,因为我说了整个bean初始化过程都在里面体现了;
我先把spring源码贴出来,读者可以忽略这里,因为下面会精简代码;
之所以贴出源码就是想告诉读者,为了研究循环依赖,本文中的很代码我是做了删减的;
getSingleton(String, ObjectFactory)源码
DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory)
//第二次调用getSingleton
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();
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions =
(this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//重要代码
//调用AbstractBeanFactory.createBean(beanName, mbd, args);
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
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;
}
}
下面是我删减后只和循环依赖有关的代码
public Object getSingleton(String beanName, ObjectFactory<?>
singletonFactory) {
//getSingleton2 -1
//从1级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
//getSingleton2 -2
if (singletonObject == null) {
//getSingleton2 -3
if (this.singletonsCurrentlyInDestruction) {
throw new Exception(beanName,
"excepition");
}
//getSingleton2 -4
beforeSingletonCreation(beanName);
//getSingleton2 -5
//调用ObjectFactory的getObject()
//调用AbstractBeanFactory.createBean(beanName, mbd, args);
singletonObject = singletonFactory.getObject();
}
return singletonObject;
}
getSingleton2-1
Object singletonObject = this.singletonObjects.get(beanName);
第二次getSingleton上来便调用了this.singletonObjects.get(beanName),直接从单例池当中获取这个对象,由于这里还没有创建故而一定返回null;
singletonObjects是一个map集合,即所谓的单例池;用大白话说spring所有的单例bean实例化好都存放在这个map当中,这也是很多读者以前认为的spring容器,但是笔者想说这种理解是错误的,因为spring容器的概念比较抽象,而单例池只是spring容器的一个组件而已;
但是你如果一定要找一个平衡的说法,只能说这个map——singletonObjects仅仅是狭义上的容器;比如你的原型bean便不在这个map当中,所以是狭义的spring容器;下图为这个map在spring源码当中的定义
getSingleton2-2
//上面解释了,在spring 初始化bean的时候这里肯定为空,故而成立
if (singletonObject == null) {
getSingleton2-3
if (this.singletonsCurrentlyInDestruction) {
throw new Exception(beanName,"excepition");
}
这行代码其实比较简单,判断当前实例化的bean是否正在销毁的集合里面;spring不管销毁还是创建一个bean的过程都比较繁琐,都会先把他们放到一个集合当中标识正在创建或者销毁;所以如果你理解了前面那个正在创建集合那么这个正在销毁集合也就理解了;但是不理解也没关系,下面会分析这些集合; 如果一个bean正在创建,但是又正在销毁那么则会出异常;
为什么会有这种情况?
其实也很简单,多线程可能会吧;
getSingleton2-4
beforeSingletonCreation(beanName);
这段代码就比较重要了,关于上面说那个正在创建和正在销毁的集合;这段代码就能解释,所以如果上面你没看明白那个集合的意义,笔者这里用spring源码来说明一下;先看看当代码执行到这里的时候语境
当spring觉得可以着手创建bean的时候,首先便是调beforeSingletonCreation(beanName);
判断当前正在实例化的bean是否存在正在创建的集合当中,说白了就是判断当前是否正在被创建;因为spring不管创建原型bean还是单例bean,当他需要正式创建bean的时候他会记录一下这个bean正在创建(add到一个set集合当中);
故而当他正式创建之前他要去看看这个bean有没有正在被创建(是否存在集合当中);
为什么spring要去判断是否存在这个集合呢?
原因很多除了你们能想到了(你们能想到的基本不会出现,比如并发啊,重复创建什么的,因为他已经做了严格并发处理),
其实这个集合主要是为了循环依赖服务的,怎么服务的呢?慢慢看吧,首先我们来看下这行 代码的具体内容
protected void beforeSingletonCreation(String beanName) {
// singletonsCurrentlyInCreation是一个set
// set调用add方法 底层走的是map的put方法
// map put 新值的时候 会将旧值返回和null 做 = = 操作 返回的是一个boolean值
// 也就是说 如果当前bean已经加入了singletonsCurrentlyInCreation
// 再加入的时候就会报错
if (!this.inCreationCheckExclusions.contains(beanName) &&
!this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
1.this.inCreationCheckExclusions.contains(beanName)
这里是判断当前需要创建的bean是否在Exclusions集合,被排除的bean,程序员可以提供一些bean不被spring初始化(哪怕被扫描到了,也不初始化),那么这些提供的bean便会存在这个集合当中;
2.this.singletonsCurrentlyInCreation.add(beanName)
如果当前bean不在排除的集合当中,那么则把这个bean添加到singletonsCurrentlyInCreation(当然这里只是把bean名字添加到集合,为了方便我们直接认为把bean添加到集合吧,因为他能根据名字能找打对应的bean);
关于singletonsCurrentlyInCreation的定义
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
其实就是一个set集合,当运行完this.singletonsCurrentlyInCreation.add(beanName) 之后结果大概如下图这样
结果分析:当代码运行完this.singletonsCurrentlyInCreation.add(beanName)之后可以看到singletonsCurrentlyInCreation集合当中只存在一个x,并且后天并没有执行x的构造方法,说明spring仅仅是把x添加到正在创建的集合当中,但是并没有完成bean的创建(因为连构造方法都没调用);
请一定注意这个集合的数据情况(目前只有一个x);
因为这和循环依赖有天大的关系;add完x之后代码接着往下执行;
getSingleton2-5
singletonObject = singletonFactory.getObject();
可能有读者已经忘记了singletonFactory这个对象怎么来的了;笔者再把代码贴一遍吧
ObjectFactory<?> singletonFactory = new ObjectFactory(){
public Object getObject(){
//其实这是个抽象类,不能实例化
//createBean是子类实现的,这里就不关心了
//你就理解这不是一个抽象类吧
AbstractBeanFactory abf = new AbstractBeanFactory();
Object bean = abf.createBean(beanName, mbd, args);
return bean;
};
};
//传入 beanName 和singletonFactory 对象
sharedInstance = getSingleton(beanName,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);
}
//验证完要真正开始创建对象 先标识该bean正在被创建
//因为bean创建过程复杂步骤很多需要标识
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions =
(this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
/***
* singletonFactory 即 AbstractBeanFactory
* singletonFactory是函数式接口
* 注意是在这里创建的bean
* 具体创建过程看 singletonFactory
*/
singletonObject = singletonFactory.getObject();
//修改newSingleton为true
newSingleton = true;
}catch (IllegalStateException ex) {
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);
}
//newSingleton为true
if (newSingleton) {
//加入一级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//加入1级
//从2级 3级删除
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
singletonFactory.getObject();调用的就是上面代码中getObject方法,换言之调用的是AbstractBeanFactory#createBean(beanName, mbd, args);
把创建好的bean返回出来;
至此第二次getSingleton方法结束,bean通过singletonFactory.getObject();
调用AbstractBeanFactory#createBean(beanName, mbd, args);创建完成;
接下来分析createBean的源码,继续探讨循环依赖的原理。
AbstractAutowireCapableBeanFactory#createBean()方法中调用了
AbstractBeanFactory#doCreateBean方法创建bean;
结果分析:因为执行完doCreateBean之后X和Y的构造方法都已经完成了调用,说明这个方法里面对X做了实例化,也就是把bean创建好了,而且完成了循环依赖(因为Y的构造方法也打印说明X在完成属性注入的时候注入了Y,所以Y也实例化了,Y bean也创建好了);
接下来重点分析这个doCreateBean方法内容。
AbstractBeanFactory#doCreateBean
我先给出这个方法的源码全貌;重点我用红色标记了,并且会在进行代码解析;黄色线下面的读者可以不用管,和本文内容没多大关系;
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper =
this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/***
* 创建bean实例 仅仅是创建bean实例
* 1.判断是否存在Supplier和Factory-Method如果有那么就使用并创建实例
* 否则就选择使用构造函数进行构造
* 2.计算构造函数至少有几个参数 选择构造函数
* 3.选择构造函数的参数 下标&通用
* 4.计算构造函数的参数权重
* instanceWrapper实现了 ConfigurablePropertyAccessor
* 是一个包装类 该类的属性可以编辑
* instanceWrapper有一个属性WrappedInstance 里面放的就是我们构造的实例
* instanceWrapper实现了 ConfigurablePropertyAccessor
* 是一个包装类 该类的属性可以编辑
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//允许 post-processors 修改 beanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//调用BeanPostProcessor的
//postProcessMergedBeanDefinition(mbd, beanType, beanName);
//其实applyMergedBeanDefinitionPostProcessors主要做的事就是用处理器把属性和 //方法上的自动装配的信息记录下来,放到bean定义里,后面进行填充的时候可以用到
//其中就包括CommonAnnotationBeanPostProcessor的生命周期方法和webService, //ejb,Resource注解信息
//以及AutowiredAnnotationBeanPostProcessor的Autowired和Value注解信息。
//https://blog.csdn.net/wangwei19871103/article/details/105127412
//https://blog.csdn.net/wangwei19871103/article/details/105139065
applyMergedBeanDefinitionPostProcessors
(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException();
}
mbd.postProcessed = true;
}
}
/***
* 是否需要提前暴露的判断条件:
* 1.是单例
* 2.允许循环依赖
* 3.bean正在被创建
*/
boolean earlySingletonExposure = (mbd.isSingleton() &&
this.allowCircularReferences &&
/***
* singletonObjects 一级缓存池
* earlySingletonObjects 二级缓存池
* singletonFactories 三级缓存池
* 此时是加入三级缓存。singletonFactories存放的是 ObjectFactory
*/
addSingletonFactory(
beanName,
// 在这里生成代理对象
// 也就是ObjectFactory的getObject方法
// 调用的是getEarlyBeanReference(beanName, mbd, bean)
() -> getEarlyBeanReference(beanName, mbd, bean)
);
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
/***
* 1.属性填充
* 2.处理属性依赖
注意:在这里的时候A需要填充B 去查找B 然后开启了B的初始化
B运行到这里的时候,也要处理属性依赖,需要A。
这个时候就到三级缓存中拿到了ObjectFactory,
调用ObjectFactory的getObject的方法
*/
populateBean(beanName, mbd, instanceWrapper);
/***
1.invokeAwareMethods(beanName, bean);
如果bean实现了以下接口
BeanNameAware, BeanFactoryAware, ApplicationContextAware
则调用对应接口的方法
2.applyBeanPostProcessorsBeforeInitialization
3.InitializingBean#afterPropertiesSet
4.invokeInitMethods,初始化bean
5.applyBeanPostProcessorsAfterInitialization
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals
(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}else {
throw new BeanCreationException();
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping
&& hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans
= new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly
(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException();
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException();
}
return exposedObject;
}
读者可以好好看看下图:方便你阅读下面的代码解析
doCreateBean -1
instanceWrapper = createBeanInstance(beanName, mbd, args);
createBeanInstance 顾名思义就是创建一个实例,注意这里仅仅是创建一个实例对象,还不能称为bean;因为我文章一开头就解释了什么是bean,什么是对象;
1.spring bean——受spring容器管理的对象,可能经过了完整的spring bean生命周期(为什么是可能?难道还有bean是没有经过bean生命周期的?答案是有的,具体我们后面文章分析),最终存在spring容器当中;一个bean一定是个对象
2.对象——任何符合java语法规则实例化出来的对象,但是一个对象并不一定是spring bean;
同样用debug来说明一下:
运行完createBeanInstance之后控制打印了X构造方法的内容,说明X对象已经被创建了,但是这个时候的x不是bean,因为bean的生命周期才刚刚开始;
这个createBeanInstance方法是如何把对象创建出来的呢?
对应文章开头说的bean的生命周期一共17步,其中的第8步(推断构造方法)和第9步(利用构造方法反射来实例化对象);
具体如何推断构造方法我会在后面的博客分析;这里截个图看看代码就行,不做分析;
(17条消息) 99%的人答不对Spring推断构造方法!打破你三观!!!(范例→源码)_小龙JWY的博客-CSDN博客
因为推断构造方法笔者以为是属于spring源码中特别重要和特别难的一块知识推断构造方法的代码比较长,读者可以多看几遍;
至此x对象已经实例化出来,代码往下执行到合并beanDefinition,看图吧
doCreateBean-2
//需要提前暴露
boolean earlySingletonExposure =
(mbd.isSingleton() &&
this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
/***
* singletonObjects 一级缓存池
* earlySingletonObjects 二级缓存池
* singletonFactories 三级缓存池
* 加入三级缓存 singletonFactories的是ObjectFactory
*/
addSingletonFactory(
beanName,
// 在这里生成代理对象
() -> getEarlyBeanReference(beanName, mbd, bean)
);
}
这段代码其实比较简单,就是给earlySingletonExposure这个布尔类型的变量赋值;
这个变量的意义是判断是否支持开启了循环依赖;
如果返回true则spring会做一些特殊的操作来完成循环依赖;
如果返回false,则不会有特殊操作;
那么判断需要提前暴露的earlySingletonExposure布尔变量的赋值逻辑是怎样的呢?
上面代码可知三个条件做&&运算,同时成立才会返回true;
- 1.是单例
- 2.允许循环依赖
- 3.bean正在被创建
1.mbd.isSingleton();
判断当前实例化的bean是否为单例;再一次说明原型是不支持循环依赖的;
因为如果是原型这里就会返回false,由于是&&运算,整个结果都为false;
在本文环境里X是默认单例的,故而整个条件是true。
2.this.allowCircularReferences;
整个全局变量spring 默认为true;当然spring提供了api供程序员修改,这个在本文开头笔者解释过(笔者是通过修改spring源码来改变这个值为false),在没有修改的情况下这里也返回true
3.isSingletonCurrentlyInCreation(beanName);
判断当前正在创建的bean是否在正在创建bean的集合当中;还记得前文笔者已经解释过singletonsCurrentlyInCreation这个集合现在里面存在且只有一个x;故而也会返回true;
其实这三种情况需要关心的只有第二种;
因为第一种是否单例一般都是成立的,因为如果是原型的循环依赖前面代码已经报错了;压根不会执行到这里;
第三种情况也一般是成立,因为这个集合是spring操作的,没有提供api给程序员去操作;
而正常流程下代码执行到这里,当前正在创建的bean是一定在那个集合里面的;
换句话说这三个条件1和3基本恒成立;
唯有第二种情况可能会不成立,因为程序员可以通过api来修改第二个条件的结果;
spring的循环依赖,不支持原型,不支持构造方法注入的饥渴加载的bean;
默认情况下单例bean是支持循环依赖的,但是也支持关闭,关闭的原理就是设置
allowCircularReferences=false;spring提供了api来设置这个值;
至此我们知道boolean earlySingletonExposure=true即需要提前暴露,那么代码接着往下执行;
判断这个变量;
if成立,进入分支;
doCreateBean-3
//参数bean是实例化但是还没初始化的bean
addSingletonFactory
(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//这段代码又用了lamda表达式;笔者为了初学者看懂,还是改成传统代码
ObjectFactory<?> singletonFactory = new ObjectFactory<?>(){
public T getObject(){
//至于这个getEarlyBeanReference方法的代码,后面再来说
// 现在可以理解为就是返回 bean
getEarlyBeanReference(beanName, mbd, bean);
//getEarlyBeanReference 的代码稍微复杂一点,可以简单理解为下面这样
/***
getEarlyBeanReference(beanName, mbd, bean){
return bean;
}
***/
}
}
//也就是singletonFactory.getObject();其实就是返回当前正在实例化的bean
//改完之后的代码可以理解成这样:
//addSingletonFactory(beanName,singletonFactory);
addSingletonFactory(beanName,singletonFactory);顾名思义添加一个ObjectFactory;
其实这里要非常注意,因为大部分资料里面在说到spring循环依赖的时候都说是提前暴露一个半成品bean;
笔者觉得这个不严格;甚至算错误了。
所谓的提前暴露就是这里,但是我们看到源码并不是add一个bean,而是add一个工厂对象singletonFactory;
两种说法有什么区别呢?
区别可大了,简直天壤之别;我们慢慢分析;这里bean和工厂有什么区别呢?
在当前的语境下面bean就是x对象经历完spring生命周期之后的实例;
所谓的半成品bean,可能还没有经历完整的生命周期的实例;
而工厂对象呢?
如果你去ObjectFactory的源码或者直接顾名思义他是一个能够产生对象的工厂,或者叫能够产生bean的工厂;
换句话说bean是一个产品,而工厂是产生这些产品的公司;
那么spring在这里add的是singletonFactory这个工厂对象(这个工厂可以产生半成品对象),而不是一个半成品对象;
将来拿出来的时候是得到工厂,继而通过工厂得到半成品bean.
当然说了这么多,可能你还是没明白为什么需要在这里add这个工厂对象呢?还有add到哪里去呢?
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
/***
* 加入3级缓存
*/
this.singletonFactories.put(beanName, singletonFactory);
/***
* 从2级缓存移除
*/
this.earlySingletonObjects.remove(beanName);
/****
* 将beanName加入已注册实例
*/
this.registeredSingletons.add(beanName);
}
}
}
/** Cache of singleton objects: bean name to bean instance.一级缓存 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of early singleton objects: bean name to bean instance. 二级缓存 */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** Cache of singleton factories: bean name to ObjectFactory. 三级缓存 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
singletonObjects存放的是成品。
earlySingletonObjects存的是半成品。
singletonFactories存的是工厂对象。
通过代码可以得知singletonFactory主要被add到singletonFactories中;
至于为什么要add到这个singletonFactories?
主要了循环依赖,提前暴露这个工厂;
当然如果你不理解为什么要提前暴露,没关系往下看,看完文章一定会知道的;
保持好习惯照例画个图,让读者知道现在的情况吧
当然这里还是用一幅图来描述一下这个三个map的各种情况吧。注意下面图里的三级缓存和的二级缓存搞反了。
一级缓存:可能存在很多bean,比如spring各种内置bean,比如你项目里面其他的已经创建好的bean,但是在X的创建过程中,一级缓存中绝对是没有xbean的,也没用y;因为spring创建bean默认的顺序是根据字母顺序的;
singletonFactories:里面现在仅仅存在一个工厂对象,对应的key为x的beanName,并且这个bean工厂对象的getObect方法能返回现在的这个时候的x(半成品的xbean) put完成之后,代码接着往下执行;
earlySingletonObjects:姑且认为里面什么都没有吧
doCreateBean-4:属性填充
AbstractAutowireCapableBeanFactory#populateBean
populateBean(beanName, mbd, instanceWrapper);
//populateBean方法中处理属性依赖
applyPropertyValues(beanName, mbd, bw, pvs);
//applyPropertyValues方法中调用resolveValueIfNecessary解决依赖的属性
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//在resolveValueIfNecessary方法中调用resolveReference获取依赖的属性
return resolveReference(argName, ref);
//在resolveReference方法中调用getBean
//在getBean中调用doGetBean获取依赖的bean 即 现在去实例化并初始化bean
bean = this.beanFactory.getBean(refName);
//上面的方法正好是一个层级
populateBean这个方法可谓大名鼎鼎,主要就是完成属性注入,也就是大家常常说的自动注入;
假设本文环境中的代码运行完这行代码那么则会注入y,而y又引用了x,所以注入进来的y对象,也完成了x的注入;
什么意思呢?首先看一下没有执行populateBean之前的情况
没有执行populateBean之前只实例化了X,Y并没实例化,那么Y也不能注入了;
接下来看看执行完这行代码之后的情况
populateBean里面的代码以后我更新文章来说明,本文先来猜测一下这个方法里面究竟干了什么事;
x 填充 y (简称 xpy)
首先肯定需要获取y,调用getBean(y),getBean的本质上文已经分析过货进入到第一次调用getSingleton,
读者可以回顾一下上文我对doGetBean方法名字的解释里说了这个方法是创建bean和获取共用的;
第一次getSingleton会从单例池获取一下y,如果y没有存在单例池则开始创建y;
创建y的流程和创建x一模一样,都会走bean的生命周期;比如把y添加到正在创建的bean的集合当中。
推断构造方法,实例化y,提前暴露工厂对象( 里面现在有两个工厂了,分别是x和y)等等。。。。重复x的步骤;
直到y的生命周期走到填充x的时候,第一次调用getSingletion(String,Boolean)获取x,这里问个问题,能否获取到x呢?
在回答这个问题之前我们先把该画的图贴出来,首先那个正在被创建bean的集合已经不在是只有一个x了;(读者可以对比一下上文的图)
然后我们再把x 填充 y 到 y填充x 的流程图贴出来,请读者仔细看看
是否能够获取到x呢?
首先我们想如果获取失败则又要创建x—>实例化x—填充属性----获取y--------。。。。。。。就无限循环了;
所以结果是完成了循环依赖,那么这里肯定能够获取到x;那么获取到x后流程是怎样呢?
那么为什么能够获取到x呢?讲道理联系上文第一次调用getSingleton是无法获取到x的?因为我们上面说过第一次调用getSingleton是从单例池当中获取一个bean,但是x显然没有完成生命周期(x只走到了填充y,还有很多生命周期没走完),所以应该是获取不到的?
为了搞清楚这个原因得去查看第一次getSingleton的源码;如果读者有留意的话笔者前面只是凭只管告诉你第一次getSingleton是从单例池当中获取一个bean,并没有去证明,也就是没有去分析第一次getSingleton的源码;
而且我在总结第一次getSingleton的时候用了目前这个词; 显然这是笔者前面故意挖的坑,所以各位读者在阅读别人的文章或者书籍的时候一定要小心验证;包括笔者的文章如果有错误一定记得告诉我;
下面来开始对第一次getSIngleton源码做深入分析;首先把源码以及我写的注释贴出来,分为图片和源代码,建议大家看图片,可读性好。
getSingleton(String, false)
protected Object getSingleton(String beanName, boolean allowEarlyReference){
//从单例池当(一级缓存)中直接拿 肯定拿不到
Object singletonObject = this.singletonObjects.get(beanName);
//如果这个时候是x注入y,y不存在创建y,y注入x,获取x的时候
//x不在singletonObjects中
//第一个singletonObject == null成立
//第二个条件判断x是否存在正在创建bean的集合当中,前面我们分析过,成立
//进入判断
if (singletonObject == null
&& isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//先从earlySingletonObjects拿x?为什么先从2级缓存拿?下文解释
singletonObject = this.earlySingletonObjects.get(beanName);
//讲道理是拿不到的
//因为这三个map现在只有singletonFactories中存了2个工厂对象
//即x和y的工厂对象
//earlySingletonObjects拿到的singletonObject也是null
//第一个条件成立
//第二个条件allowEarlyReference=true,这个是写死的true
//就是spring循环依赖的开关,默认为true
//进入if分支
if (singletonObject == null && allowEarlyReference) {
//从3级缓存中获取一个 singletonFactory,回顾前文,能获取到
//由于这里的beanName=x,故而获取出来的工厂对象
//能产生一个x半成品bean
ObjectFactory<?> singletonFactory =
this.singletonFactories.get(beanName);
//由于获取到了,进入if分支
if (singletonFactory != null) {
//调用工厂对象的getObject()方法,产生一个x的半成品bean
//怎么产生的?下文解释,比较复杂
//这里的singletonFactory指的是
// getEarlyBeanReference(beanName, mbd, bean)
singletonObject = singletonFactory.getObject();
//拿到了半成品的xbean之后,把他放到earlySingletonObjects
//为什么?下文解释
this.earlySingletonObjects
.put(beanName, singletonObject);
//然后从singletonFactories清除掉x的工厂对象?
//为什么?下文解释
this.singletonFactories.remove(beanName);
}
}
}
}
针对上面的源码我做一个简单的总结:
首先spring从单例池当中获取x,前面说过获取不到。
然后判断是否在正在创建bean的集合当中,前面分析过这个集合现在存在x,和y;
所以if成立进入分支;进入分支spring直接从earlySingletonObjects中获取x。
根据前面的分析earlySingletonObjects当中现在什么都没有,故而返回nll;
进入下一个if分支,从singletonFactories中获取一个ObjectFactory工厂对象;
根据前面分析,singletonFactories中存在x,故而可以获取到;
跟着调用singletonFactory.getObject();拿到一个半成品的x bean对象;
然后把这个x对象放到earlySingletonObjects,同时把singletonFactories中x清除。
此时三级缓存singletonFactories中只存在一个y了,而二级缓存earlySingletonObjects中多了一个x
问题1.为什么首先是从三级缓存中取呢?
主要是为了性能,因为三级缓存中存的是一个x对象,如果能取到则不去二级找了;哪有人会问二级有什么用呢?为什么一开始要存工厂呢?为什么一开始不直接存三级缓存?这里稍微有点复杂,如果直接存到三级缓存,只能存一个对象,假设以前存这个对象的时候这对象的状态为xa,但是我们这里y要注入的x为xc状态,那么则无法满足;但是如果存一个工厂,工厂根据情况产生任意xa或者xb或者xc等等情况;比如说aop的情况下x注入y,y也注入x;而y中注入的x需要加代理(aop),但是加代理的逻辑在注入属性之后,也就是x的生命周期周到注入属性的时候x还不是一个代理对象,那么这个时候把x存起来,然后注入y,获取、创建y,y注入x,获取x;拿出来的x是一个没有代理的对象;但是如果存的是个工厂就不一样;首先把一个能产生x的工厂存起来,然后注入y,注入y的时候获取、创建y,y注入x,获取x,先从三级缓存获取,为null,然后从二级缓存拿到一个工厂,调用工厂的getObject();spring在getObject方法中判断这个时候x被aop配置了故而需要返回一个代理的x出来注入给y。当然有的读者会问你不是前面说过getObject会返回一个当前状态的xbean嘛?我说这个的前提是不去计较getObject的具体源码,因为这块东西比较复杂,需要去了解spring的后置处理器功能,这里先不讨论,总之getObject会根据情况返回一个x,但是这个x是什么状态,spring会自己根据情况返回;
问题2.为什么要从二级缓存remove?
因为如果存在比较复杂的循环依赖可以提高性能;比如x,y,z相互循环依赖,那么第一次y注入x的时候从二级缓存通过工厂返回了一个x,放到了三级缓存,而第二次z注入x的时候便不需要再通过工厂去获得x对象了。因为if分支里面首先是访问三级缓存;至于remove则是为了gc吧;
至此循环依赖的内容讲完,有错误欢迎指正,欢迎留言提问;如果觉得笔者写的对你有帮助可以多多点赞转发吧;
总结循环依赖的过程
A、B 类 setter 循环依赖的创建过程
1.getSingleton("a", true) 获取a,会从一级缓存中找a(一级缓存该bean为空且当前 bean 正在创建才能去2级缓存拿),然后直接返回空,此时 3 个级别的缓存中都没有 a
2.调用getSingleton(String, ObjectFactory),ObjectFactory是调用createBean方法
sharedInstance = getSingleton(beanName,
() -> {
return createBean(beanName, mbd, args);
});
3.将a添加到正在创建的集合singletonsCurrentlyInCreation中
4.调用 ObjectFactory.getObject()即createBean方法
5.进入doCreateBean方法,推断构造方法、反射调用构造方法实例化bean,这个时候a对象是早期的a,属于半成品。
6.判断需要提前暴露 加入三级缓存放入的是SingletonFactory,SingletonFactory有半成品的引用:
addSingletonFactory(beanName,
() -> getEarlyBeanReference(beanName, mbd, bean));
7.调用 populateBean方法,为a做属性填充操作,注入依赖的对象,发现 setB 需要注入b
8.调用getSingleton(String, ObjectFactory),ObjectFactory是调用createBean方法
sharedInstance = getSingleton(beanName,
() -> {
return createBean(beanName, mbd, args);
});
9.将b添加到正在创建的集合singletonsCurrentlyInCreation中
10.调用 ObjectFactory.getObject()即createBean方法
11.进入doCreateBean方法,反射调用构造方法实例化b,这个时候b对象是早期的b,属于半成品
12.判断需要提前暴露 加入三级缓存:addSingletonFactory(beanName,
() -> getEarlyBeanReference(beanName, mbd, bean));
13.调用populateBean方法,为b做属性填充操作,注入依赖的对象,发现 setA 需要注入a
14.调用 getSingleton("a", true) 获取a,会从3级缓存中找a。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//是否应创建早期引用 allowEarlyReference is true
Object singletonObject = this.singletonObjects.get(beanName);
//一级缓存中该bean为空 且 当前 bean 正在创建才能去2级缓存拿
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//2级缓存中获取
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) {
//3级缓存中获取 获取的是一个ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用ObjectFactory的getObject方法获取对象
singletonObject = singletonFactory.getObject();
//放入2级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从3级缓存移除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
一级缓存该bean为空且当前 bean 正在创建才能去2级缓存拿,2级缓存是空。
2级缓存是空并且允许循环依赖才能从3级缓存拿。
从3级缓存中获取调用ObjectFactory
然后调用ObjectFactory#getObject获取bean。
即调用getEarlyBeanReference方法获取a。
在获取a的时候会提前获取a的代理对象
在获取a的时候会提前获取a的代理对象
在获取a的时候会提前获取a的代理对象
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
//1.不是合成的
//2.存在InstantiationAwareBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp
= (SmartInstantiationAwareBeanPostProcessor) bp;
//AbstractAutoProxyCreator.getEarlyBeanReference
exposedObject
= ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
//注意这里this.earlyProxyReferences.put(cacheKey, bean);
//注意这里this.earlyProxyReferences.put(cacheKey, bean);
//注意这里this.earlyProxyReferences.put(cacheKey, bean);
//这里把bean放入了缓存earlyProxyReferences
//后面还要取出来用
//放进去的目的是:后面用来比较代理的bean对象和提前暴露的bean对象是不是还是一个对象
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
此时 a 会从第 3 级缓存中被移到第 2 级缓存,然后将其返回给 b 使用,此时 a 是个半成品(属性还未填充完毕)3级缓存是个工厂,工厂创建对象完毕就没用了,所以需要从三级缓存移除,加入二级缓存
15.b 通过 setA 将 14 中获取的 a 注入到 b 中,b填充属性完毕 然后调用
b= initializeBean("b", b, mbd)
initializeBean方法流程如下:
1.invokeAwareMethods,设置Spring的上下文组件
2.BeanPostProcessor 的 before 方法
3.invokeInitMethods
4.BeanPostProcessor 的 after 方法
此时b的生命周期执行完毕,a填充完属性准备执行initializeBean方法。
16.调用`Object earlySingletonReference = getSingleton(beanName, false);`
即getSingleton("b", false)获取a,注意这个时候第二个参数是false,这个参数为 false 的时候,只会从前 2 级缓存中尝试获取b,此时1级缓存 2级缓存都没有,只有3级缓存有1个工厂对象,所以获取的是空。
注意:如果不是空,会判断initializeBean("b", b, mbd)返回的对象和getSingleton("b", false)获取的对象是不是1个对象。因为对b进行处理完毕,可能对b进行改变,有可能导致b和原始的b不是同一个对象了。
所以需要判断提前暴露的b和原始的b是不是一个对象。
接着返回DefaultSingletonBeanRegistry#getSingleton(String,ObjectFactory\<?\>)将b加入1级缓存。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
此时b的生命周期执行完毕,a填充完属性准备执行initializeBean方法。我们接着a的生命周期往下看
//将bean的引用给exposedObject
//此时bean和exposedObject都指向的是bean:A@1828
//此时bean中的属性b是null
Object exposedObject = bean;
try {
//填充属性,针对的是instanceWrapper,instanceWrapper中有bean的引用
populateBean(beanName, mbd, instanceWrapper);
/****
initializeBean方法对exposedObject做了代理?
相信很多小伙伴还在这里犯迷糊
没有在这里做代理
没有在这里做代理
没有在这里做代理
代理在循环依赖的过程中已经被做掉了
具体的时机是创建完B,在B初始化填充属性的时候发现需要依赖A,此时从三级缓存中取出A。
此时A就已经是被代理的对象了
那么这里做了什么?这里只是做了判断直接返回了bean。
直接上代码:AbstractAutoProxyCreator#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//从缓存中拿出来对象 判断成立 直接return bean
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
也就是说return的bean还是bean的实例,不是bean的代理对象
所以下面的exposedObject == bean条件成立
****/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}catch (Throwable ex) {
if (ex instanceof BeanCreationException
&& beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//获取的早期对象也就是代理对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//如果实例化的bean和初始化以后的bean还是1个
//将bean的代理对象赋值给bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException();
}
}
}
}
虽然b没有做判断但是a在二级缓存是存在的。所以a做了这个判断。
这里最后的返回的是 initializeBean("b", b, mbd)方法返回的对象
此时b创建完毕 最后b会从第2 3级缓存中被移除,然后被丢到1级缓存
注意b没有进入二级缓存
注意b没有进入二级缓存
注意b没有进入二级缓存
17.b 返回给 a,然后 b 被通过 A 类中的 setB 注入给 a
18.a 的 populateBean 执行完毕,即:完成属性填充,到此时 a 已经注入到 b 中了
19.调用a= initializeBean("a", a, mbd)对 a 进行处理,这个内部可能对 a 进行改变,有可能导致 a 和原始的 a 不是同一个对象了
1.invokeAwareMethods,设置Spring的上下文组件
2.BeanPostProcessor 的 before 方法
3.invokeInitMethods
4.BeanPostProcessor 的 after 方法
20.调用getSingleton("a", false)获取 a,注意这个时候第二个参数是 false,这个参数为 false 的时候,只会从前 2 级缓存中尝试获取 a,而 a 在步骤 11 中已经被丢到了第 2 级缓存中,所以此时这个可以获取到 a,这个 a 已经被注入给 b 了。
因为对a进行处理完毕,可能对a进行改变,有可能导致a和原始的a不是同一个对象了。所以需要判断提前暴露的a和原始的a是不是一个对象。
所以这里最后的返回的是 initializeBean("a", a, mbd) 的对象
此时a创建完毕 最后a会从第2 3级缓存中被移除,然后被丢到1级缓存
21.此时判断注入给 b 的 a 和通过initializeBean方法产生的 a 是否是同一个 a,不是同一个,则弹出异常
22.此时a创建完毕 最后b会从第2 3级缓存中被移除,然后被丢到1级缓存
为什么exposedObject == bean 能成立
先执行A的实例化,再执行A的初始化,A初始化填充属性需要B。此时会开启B的生命周期。
执行B的实例化,再执行B的初始化,B初始化填充属性需要A。
调用 getSingleton("a", true) 获取a,会从3级缓存中找a。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//是否应创建早期引用 allowEarlyReference is true
Object singletonObject = this.singletonObjects.get(beanName);
//一级缓存中该bean为空 且 当前 bean 正在创建才能去2级缓存拿
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//2级缓存中获取
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) {
//3级缓存中获取 获取的是一个ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用ObjectFactory的getObject方法获取对象
singletonObject = singletonFactory.getObject();
//放入2级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从3级缓存移除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
1级缓存该bean为空且当前 bean 正在创建才能去2级缓存拿,2级缓存是空。2级缓存是空并且允许循环依赖才能从3级缓存拿。从3级缓存中获取调用ObjectFactory然后调用ObjectFactory#getObject获取bean。即调用getEarlyBeanReference方法获取a。在调用getEarlyBeanReference方法获取a的时候会提前获取a的代理对象。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
//1.不是合成的
//2.存在InstantiationAwareBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp
= (SmartInstantiationAwareBeanPostProcessor) bp;
//AbstractAutoProxyCreator.getEarlyBeanReference
exposedObject
= ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
注意这里this.earlyProxyReferences.put(cacheKey, bean);这里把bean放入了缓存earlyProxyReferences,后面还要取出来用。放进去的目的是:后面用来比较代理的bean对象和提前暴露的bean对象是不是还是一个对象
接下来返回DefaultSingletonBeanRegistry#getSingleton(String, boolean)
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//是否应创建早期引用 allowEarlyReference is true
Object singletonObject = this.singletonObjects.get(beanName);
//一级缓存中该bean为空 且 当前 bean 正在创建才能去2级缓存拿
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//2级缓存中获取
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) {
//3级缓存中获取 获取的是一个ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用ObjectFactory的getObject方法获取对象
singletonObject = singletonFactory.getObject();
//放入2级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从3级缓存移除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
此时 a 会从第 3 级缓存中被移到第 2 级缓存,然后将其返回给 b 使用,此时 a 是个半成品(属性还未填充完毕)3级缓存是个工厂,工厂创建对象完毕就没用了,所以需要从三级缓存移除,加入二级缓存
b 通过 setA 将 14 中获取的 a 注入到 b 中,b填充属性完毕 然后调用 b = initializeBean("b", b, mbd)
执行完b的initializeBean方法
16.调用Object earlySingletonReference = getSingleton(beanName, false);
即getSingleton("b", false)获取a,注意这个时候第二个参数是false,这个参数为 false 的时候,只会从前 2 级缓存中尝试获取b,此时1级缓存 2级缓存都没有,只有3级缓存有1个工厂对象,所以获取的是空。
注意:如果不是空,会判断initializeBean("b", b, mbd)返回的对象和getSingleton("b", false)获取的对象是不是1个对象。因为对b进行处理完毕,可能对b进行改变,有可能导致b和原始的b不是同一个对象了。 所以需要判断提前暴露的b和原始的b是不是一个对象。
接着返回DefaultSingletonBeanRegistry#getSingleton(String,ObjectFactory<?>)将b加入1级缓存。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
此时b的生命周期执行完毕,a填充完属性准备执行initializeBean方法。我们接着a的生命周期往下看
//将bean的引用给exposedObject
//此时bean和exposedObject都指向的是bean:A@1828
//此时bean中的属性b是null
Object exposedObject = bean;
try {
//填充属性,针对的是instanceWrapper,instanceWrapper中有bean的引用
populateBean(beanName, mbd, instanceWrapper);
/****
initializeBean方法对exposedObject做了代理?
相信很多小伙伴还在这里犯迷糊
没有在这里做代理
没有在这里做代理
没有在这里做代理
代理在循环依赖的过程中已经被做掉了
具体的时机是创建完B,在B初始化填充属性的时候发现需要依赖A,此时从三级缓存中取出A。
此时A就已经是被代理的对象了
那么这里做了什么?这里只是做了判断直接返回了bean。
直接上代码:AbstractAutoProxyCreator#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//从缓存中拿出来对象 判断成立 直接return bean
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
也就是说return的bean还是bean的实例,不是bean的代理对象
所以下面的exposedObject == bean条件成立
****/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}catch (Throwable ex) {
if (ex instanceof BeanCreationException
&& beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
//获取的早期对象也就是代理对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//如果实例化的bean和初始化以后的bean还是1个
//将bean的代理对象赋值给bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException();
}
}
}
}
至此if (exposedObject == bean)
判断为什么成立就讲完了。整个循环依赖都讲完了。