但我突然又想到 我们的关注重点是
我们知道Spring实例化(无论单例还是多例)会先进入getBean 接着会进入doGetBean 它的源码重点大致如下(不了解的话 请去看下 Spring启动过程——源码分析2 )
//先从singletonObjects拿 //拿不到 调用beforeSingletonCreation this.singletonsCurrentlyInCreation.add(beanName) 从this.singletonFactories.get(beanName).getObject() getSingleton(beanName); //经过上面的还是拿不到 //同样先从singletonObjects拿 拿不到调用createBean 进入后会进到createBeanInstance //createBeanInstance会根据实例化方式进行各自的实例化 sharedInstance = getSingleton(beanName, () -> createBean(beanName, mbd, args)) //创建完Bean放入缓存singletonFactories.put(beanName, singletonFactory) addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); !! 此时singletonObjects不存在上面的bean //填充属性 populateBean(beanName, mbd, instanceWrapper); //初始化Bean 与这里无关 exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject; 复制代码
重点 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
指向原始对象的引用通过 ObjectFactory 暴露出去 将已经实例化的bean作为参数传到方法里面,循环依赖时等到再次执行getSingleton会执行processor直接返回这个Bean
//这个方法不是很清楚,但我debug发现基本都是直接return bean getEarlyBeanReference(beanName, mbd, bean) 复制代码
Bean依赖时执行流程图 StudentA和StudentB相互依赖的情况(从左到右Bean分别是StudentA、StudentB、StudentA)
Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池” Set集合singletonsCurrentlyInCreation中,Bean标识符在创建过程中将一直保持 在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖
三种注入方式
属性注入
有参注入
setter注入
根据上边的流程图 那么三种注入方式下,实例化的过程有什么不一样呢?
实例化->填充属性
spring单例下真正实例化Bean的地方
getSingleton(beanName, singletonFactory) 复制代码
大致执行如下
Object singletonObject = this.singletonObjects.get(beanName); if(singletonObject!=null) return; //singletonsCurrentlyInCreation.add(name) 解决循环依赖 beforeSingletonCreation(beanName); //真正实例化bean 其实也就是createBean这个方法 //最终会进入到无参或者有参的实例化 singletonObject = singletonFactory.getObject(); //singletonsCurrentlyInCreation.remove(name) 解决循环依赖 afterSingletonCreation(beanName); addSingleton(beanName, singletonObject);//加入缓存 return singleObject 复制代码
spring多例下真正实例化Bean的地方
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //this.prototypesCurrentlyInCreation.set(beanName) beforePrototypeCreation(beanName); //最终会进入到无参或者有参的实例化 prototypeInstance = createBean(beanName, mbd, args) //this.prototypesCurrentlyInCreation.remove(); afterPrototypeCreation(beanName) 复制代码
afterSingletonCreation 以StudentA->StudentB->StudentA->为例
首先StudentA调用getBean进入createBeanInstance这个方法里,由于是无参实例化 会直接用反射返回一个对象bean,再调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))暴露ObjectFactory,接着进入populateBean,在这里属性还是setter注入的区别就是通过不同的方式去对StudentB赋值,一样的是都要去getBean("StudentB")->getSingleton("StudentB")->getSingleton("StudentB",()->createBean))->createBeanInstance->addSingletonFactory->populateBean->getSingleton("StudentA") 执行到这里 会直接return 刚刚addSingletonFactory时缓存的Bean
此时singletonsCurrentlyInCreation也是有StudentA、B的 只不过没有执行到getSingleton("StudentB",()->createBean)) 所以也就不会报异常
进入createBeanInstance后
有参构造函数实例化会进入autowireConstructor方法 StudentA会先去获取它参数里的StudentB 此时调用getBean->getSingleton("StudentB",()->createBean))->beforeSingletonCreation("StudentB")->createBeanInstance 再次进入autowireConstructor
StudentB会先去获取它参数里的StudentA 此时调用getBean->getSingleton->beforeSingletonCreation("StudentA")
由于每次singletonsCurrentlyInCreation.add(beanName) 此时singletonsCurrentlyInCreation已经有StudentA
singletonsCurrentlyInCreation.add(beanName)==false -> 抛出BeanCurrentlyInCreationException
首先StudentA调用getBean进入doGetBean->isPrototypeCurrentlyInCreation("StudentA")->beforePrototypeCreation("StudentA")->createBean("StudentA", mbd, args)->createBeanInstance->populate->doGetBean("StudentB")->isPrototypeCurrentlyInCreation("StudentA")->beforePrototypeCreation("StudentB")->createBean("StudentB", mbd, args)->createBeanInstance->populate->doGetBean("StudentA")->isPrototypeCurrentlyInCreation("StudentA")此时返回true 直接抛异常