Class B 需要通过构造函数注入实现 class C,而 class C 需要通过构造函数注入实现 class B.如果为 classes B 和 C 配置 beans 以相互注入,则 Spring IoC 容器会在运行时检测到此循环 reference
,并抛出BeanCurrentlyInCreationException
。
创建类B
public class B {
private C ccc;
public B(C ccc){
System.out.println("创建一个对象: 【"+this + "】");
}
}
创建类C
public class C {
private B bbb;
public C(B bbb){
System.out.println("创建一个对象: 【"+this + "】");
}
public void setBbb(B bbb) {
this.bbb = bbb;
}
}
通过构造注入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bBean" class="com.sean.spring.bean.B">
<constructor-arg ref="cBean"/>
bean>
<bean id="cBean" class="com.sean.spring.bean.C">
<constructor-arg ref="bBean"/>
bean>
beans>
测试类
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring/application-context.xml");
B bean = context.getBean(B.class);
logger.debug(bean);
}
抛出异常
如果我们不使用构造器注入,而使用setter注入就不会出现循环依赖报错问题。
setter注入
B类,创建一个set方法
public class B {
private C ccc;
public void setCcc(C ccc) {
this.ccc = ccc;
}
}
C类
public class C {
private B bbb;
public void setBbb(B bbb) {
this.bbb = bbb;
}
}
通过setter配置bean XML文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bBean" class="com.sean.spring.bean.B">
<property name="ccc" ref="cBean"/>
bean>
<bean id="cBean" class="com.sean.spring.bean.C">
<property name="bbb" ref="bBean"/>
bean>
beans>
测试通过了,打印了我们创建的B对象
如果我们通过setter注入,指定scope="prototype"
,循环依赖也会报错。
总结:同样对于循环依赖的场景,构造器注入和prototype类型的属性set注入都会初始化Bean失败。因为默认是单例的,所以单例的属性注入是可以成功的。
下边我们就从源码中去求证,Spring Bean 的加载流程程序入口
ApplicationContext context = new ClassPathXmlApplicationContext("spring/application-context.xml");
B bean = context.getBean(B.class);
第二行getBean已经看到可以获取Bean对象,那么肯定在第一步就完成了Bean的加载。
ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
//设置父级的ApplicationContext,这里是null,没什么用
super(parent);
//存储Spring配置文件的路径到本地,这里取的就是"spring/application-context.xml"
this.setConfigLocations(configLocations);
if (refresh) {
//Spring Bean的核心方法,用于刷新Spring上下文信息,定义了上下文加载的过程
this.refresh();
}
}
Spring源码比较复杂也比较多,所以我们只关注需要注意的点即可,不然很容易迷失。Spring Bean 核心方法 refresh
方法
public void refresh() throws BeansException, IllegalStateException {
//加锁,避免多线程场景下同时刷新Spring上下文
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
//这是在子类中启动refreshBeanFactory的地方
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
//设置BeanFactory的后置处理
this.postProcessBeanFactory(beanFactory);
//调用BeanFactory的后处理器,这些后处理器在Bean定义中向容器注册
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册Bean的后处理器,在Bean创建过程中调用
this.registerBeanPostProcessors(beanFactory);
//对上下文消息源进行初始化
this.initMessageSource();
//初始化上下文的事件机制
this.initApplicationEventMulticaster();
//初始化其他特殊的Bean
this.onRefresh();
//检查监听Bean并且将这些Bean向容器注册
this.registerListeners();
//实例化所有的单列
this.finishBeanFactoryInitialization(beanFactory);
//发布容器事件,结束refresh过程
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
//异常时,销毁Bean
this.destroyBeans();
//重置"active"标志
this.cancelRefresh(var9);
throw var9;
} finally {
//清空缓存
this.resetCommonCaches();
}
}
}
obtainFreshBeanFactory
方法作用就是获取刷新Spring上下文Bean工厂,我们看他里边的refreshBeanFactory
方法
protected final void refreshBeanFactory() throws BeansException {
//如果已经存在直接销毁并关闭工厂
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
//创建Ioc容器,使用的是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
//启动对BeanDefintion的载入
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
从以上源码可以看到,创建Bean工厂的时候。其实是创建的DefaultListableBeanFactory
工厂对象,这也是我们要讨论的循环依赖的关键。
接下来我们简单介绍一下loadBeanDefinitions
。
Spring Ioc容器的两大步骤就是Bean的定义和初始化,它是先定义,然后初始化和依赖注入的。
Bean的定义分为三步:
Resource
定位:这步是Sring Ioc容器根据开发者的配置,进行资源定位,在Spring开发中,通过XML或者注解配置,定位的内容也是在配置文件汇总提供的BeanDefinition
的载入:这个时候只是将Resources定位到的信息保存到Bean定义(BeanDefinition)中,此时不会创建Bean的实例。BeanDefinition
的注册,这个过程是将BeanDefinition的信息发布到Spring Ioc容器,注意,这时候仍旧没有对应的Bean的实例创建。loadBeanDefinitions
在这里主要做了这么几件事:
BeanDefinitionReader
BeanDefinitionReader
获取Resource
,也就是xml配置文件的位置,并且把文件转换成一个叫Document
的对象Document
对象转化成容器内部的数据结构(也就是BeanDefinition
),也即是将Bean定义的List、Map、Set等各种元素进行解析,转换成Managed类(Spring对BeanDefinition数据的封装)放在BeanDefinition中;这个方法是RegisterBeanDefinition
(),也就是解析的过程。BeanDefinition
对象中并设置到一个Map中以上就是Spring Ioc中Bean定义过程,如何定位,载入和注册的有兴趣的读者可以去看一下源码。可查看PropertiesBeanDefinitionReader
再回到refresh方法,在创建完beanFactory
后,执行了prepareBeanFactory
方法,这个方法做bean的准备工作。
中间有一段代码是这样的
if (!beanFactory.containsLocalBean("systemProperties")) {
beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
}
意思就是说要判断我们本地配置的bean是否要注册为单例的,进入这个方法
registerSingleton,我们会看到他有两个实现类DefaultListableBeanFactory
,DefaultSingletonBeanRegistry
,通过之前的refreshBeanFactory方法,我们已经知道创建的beanFactory是DefaultListableBeanFactory
,那DefaultSingletonBeanRegistry
很显然是单例时候创建的beanFactory,而Spring Ioc默认是单例模式。DefaultSingletonBeanRegistry
方法就是我们苦苦找寻的关键
DefaultSingletonBeanRegistry
//存储单例Bean名称,单例Bean实现映射关系
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//存储Bean名称,ObjectFactory实现映射关系
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
//存储Bean名称,预加载Bean实现映射关系
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
DefaultSingletonBeanRegistry
维护了三个Map,为什么我会专门列出它们,下边会用到。
再回到refresh方法,bean准备完成,后续就是设置后置处理器等一些初始化操作,我们重点看一下finishBeanFactoryInitialization
方法,实例化所有的non-lazy-init,里边有一个preInstantiateSingletons
方法,顾名思义就是实例化所有的单例bean。
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator();
while(true) {
while(true) {
String beanName;
RootBeanDefinition bd;
do {
do {
do {
if (!var2.hasNext()) {
var2 = beanNames.iterator();
while(var2.hasNext()) {
beanName = (String)var2.next();
Object singletonInstance = this.getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
return;
}
beanName = (String)var2.next();
//将Spring上下文的AbstractBeanDefinition转换为RootBeanDefinition
bd = this.getMergedLocalBeanDefinition(beanName);
} while(bd.isAbstract());
} while(!bd.isSingleton());
} while(bd.isLazyInit());
if (this.isFactoryBean(beanName)) {
//实例化的关键
final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean)factory).isEagerInit();
}
}, this.getAccessControlContext());
} else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
}
//isEagerInit是否需要立即加载
if (isEagerInit) {
this.getBean(beanName);
}
} else {
this.getBean(beanName);
}
}
}
}
getBean >>>doGetBean >>>createBean >>>doCreateBean
createBean不但生成了bean,还对bean进行了处理,比如实现了BeanDefinition中的init-method属性定义,Bean后置处理器等。
createBean
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
doCreateBean
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
与依赖注入关系特别密切的方法有createBeanInstance()
和populateBean()
方法,createBeanInstance()
中生成了Bean所包含的java对象,这个对象的生成有很多种不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成,这些方式都是由相关的BeanDefinition
来指定的。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//确认需要创建的Bean实例的类可以初始化
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
} else if (mbd.getFactoryMethodName() != null) {
//这里使用工厂方法对Bean进行实例化
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized(mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
//使用默认的构造函数对Bean进行实例化
return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
} else {
//使用构造函数进行实例化
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
return ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args) ? this.instantiateBean(beanName, mbd) : this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}
instantiateBean 调用 instantiate 方法
beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);
instantiate
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
if (bd.getMethodOverrides().isEmpty()) {
Constructor constructorToUse;
synchronized(bd.constructorArgumentLock) {
constructorToUse = (Constructor)bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = (Constructor)AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[])null);
}
});
} else {
constructorToUse = clazz.getDeclaredConstructor((Class[])null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
} catch (Exception var9) {
throw new BeanInstantiationException(clazz, "No default constructor found", var9);
}
}
}
//BeanUtils进行实例化,反射
return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
} else {
//使用CGLIB实例化
return this.instantiateWithMethodInjection(bd, beanName, owner);
}
}
要了解怎样使用cglib来生成Bean对象,需要看一下SimpleInstantiationStrategy
类。这个Strategy
是Spring用来生成Bean对象的默认类,它提供了两种实例化Java对象的方法,一种是通过BeanUtils,它使用了JDK的反射功能,一种是通过前面提到的CGLIB来生成, 使用SimpleInstantiationStrategy生成Java对象。
以上分析了实例化bean的整个过程,但是并没有完成整个依赖注入过程,只是实例化了对象,重要的属性的处理过程还需看populateBean
。
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//这里取得在BeanDefinition 中设置的property值
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!((PropertyValues)pvs).isEmpty()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
} else {
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
Iterator var6 = this.getBeanPostProcessors().iterator();
while(var6.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var6.next();
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
//开始进行依赖注入过程
if (continueWithPropertyPopulation) {
if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {
MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
//根据Bean的名字
if (mbd.getResolvedAutowireMode() == 1) {
this.autowireByName(beanName, mbd, bw, newPvs);
}
//根据Bean的类型
if (mbd.getResolvedAutowireMode() == 2) {
this.autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = mbd.getDependencyCheck() != 0;
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
Iterator var9 = this.getBeanPostProcessors().iterator();
while(var9.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var9.next();
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
pvs = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);
}
}
//对属性进行注入
this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}
}
}
Spring Ioc提供自动装配的方式,使用反射自动查找属性的类型或者名字,然后基于属性的类型或名字来自动匹配Ioc容器中的Bean
autowire属性是在对Bean属性进行依赖注入时起作用。对autowire属性进行处理,从而完成对Bean属性的自动依赖装配,是在populateBean中实现的。对属性autowire的处理是populateBean处理过程的一个部分。在populateBean的实现中,在处理一般的Bean之前,先对autowire属性进行处理。如果当前的Bean配置了byName和byType属性,那么调用相应的autowireByName方法和autowireByType方法。例如,对于byName,它首先通过反射机制从当前Bean中得到需要注入的属性名,然后使用这个属性名向容器申请与之同名的Bean,这样实际又触发了另一个Bean的生成和依赖注入的过程。
对autowireByName来说,它首先需要得到当前Bean的属性名,这些属性名已经在BeanWrapper和BeanDefinition中封装好了,然后是对这一系列属性名进行匹配的过程。在匹配的过程中,因为已经有了属性的名字,所以可以直接使用属性名作为Bean名字向容器索取Bean,这个getBean会触发当前Bean的依赖Bean的依赖注入,从而得到属性对应的依赖Bean。在执行完这个getBean后,把这个依赖Bean注入到当前Bean的属性中去,这样就完成了通过这个依赖属性名自动完成依赖注入的过程。
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = this.unsatisfiedNonSimpleProperties(mbd, bw);
String[] var6 = propertyNames;
int var7 = propertyNames.length;
for(int var8 = 0; var8 < var7; ++var8) {
String propertyName = var6[var8];
if (this.containsBean(propertyName)) {
//使用当前bean的属性名作为bean的名字
Object bean = this.getBean(propertyName);
pvs.add(propertyName, bean);
this.registerDependentBean(propertyName, beanName);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found");
}
}
}
Spring创建好了BeanDefinition之后呢,会开始实例化Bean,并且对Bean的依赖属性进行填充。实例化时底层使用了CGLIB或Java反射技术,最终是对属性的注入,整个流程代码较多,总结下来就是下面整个流程图
下边我们来看循环依赖问题
之前得到的结论:
通过set注入,能够解决循环依赖,可以初始化
构造器注入,或者非单例注入,不能解决循环依赖,不可以被初始化,抛出异常。
下边我们就重点关注一下从doGetBean
到populateBean
的过程。因为代码众多,我这里把主要调用的几个关键方法做成流程图。
我们主要看getSingleton
方法,可以看到获取单例bean的时候会判断三个Map是否已经存在,这其实就是本节的关键,下边具体会讲到。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//通过beanName在已经创建的Singleton集合中查找
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
//如果没找到,就去earlySingletonObjects中查找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//还没找到,就去singletonFactory 找
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//找到后放到earlySingletonObjects中
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
//将singletonFactories中的缓存删除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject != NULL_OBJECT ? singletonObject : null;
}
执行addSingletonFactory
,此时bean已经初始化,只是还没执行populateBean
方法,重要的值还没初始化放进去,但是Spring已经认为它是可复用的bean,所以看以下代码,Spring会把bean放到三级缓存中。
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized(this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
populateBean
中有autowireByName
,autowireByType
方法,无论是通过name还是type注入的,最终结果都是,如果B中注入了一个C,那么执行B中的populateBean方法时,就会调用getBean©,先把C初始化完成之后,再接着初始化B。
单例循环注入B-C-B,B中依赖C,C又依赖B
本质就是在在13步的时候拿到了三级缓存,结束了循环的getBean,解决了循环依赖问题
因为也就印证了我们上边的第一条结论:1.通过set注入,能够解决循环依赖,可以初始化
至于第二条结论:2.构造器注入,或者非单例注入,不能解决循环依赖,不可以被初始化,抛出异常。
其实这个也很好理解了,还记得instantiateBean
中instantiate
(实例化)其实就是一个new对象的过程,new对象要执行构造器,因为B中构造器注入了C,那么B在instantiate实例化时,就直接进行了C的实例化,那么B在关键的方法addSingletonFactory()
之前就去初始化了C,导致三级缓存中根本就没有B,所以发生了死循环,Spring发现后就抛出了异常。
原型模式Bean的初始化
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
} else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet(2);
beanNameSet.add((String)curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
} else {
Set<String> beanNameSet = (Set)curVal;
beanNameSet.add(beanName);
}
}
beforePrototypeCreation
会把每个正在创建的prototype
类型的beanName放到set中。并且在dogetBean
中会检查beanName是否处于创建状态,如果是则抛出异常
对原型模式的beanName进行检查
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
上一步已经把beanName放到Set中,这里判断Set包含,返回布尔类型
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return curVal != null && (curVal.equals(beanName) || curVal instanceof Set && ((Set)curVal).contains(beanName));
}
并且这个校验还在createBean之前没从流程来看,无论是构造注入还是设值注入,第二次注入同一个bean的时候执行到这里,一定会校验抛出异常,因为不能完成注入,也就不能循环依赖。
总结:Spring在InstantiateBean时执行构造器方法,构造出实例,如果是单例的话,会将它放入一个singletonBeanFactory的缓存中,再进行populateBean方法,设置属性。通过一个singletonBeanFactory的缓存解决了循环依赖的问题。
补充
网上也有博客通过一道算法解释了循环依赖的真谛,这个算法就是经典的“两数之和”
下边给出解决方法
import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i< nums.length; i++){
int complement = target - nums[i];
if (map.containsKey(complement)){
return new int[]{map.get(complement),i};
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
}
同样是定义一个Map集合,先去map中找需要的值,没有的话就将当前数字放到map中,如果找到就一起返回。
和我们所讲的三级缓存,先去缓存找bean,没有就实例化,放到map,如果有需要就冲map中取到。
好了,本篇文章到此就结束了,因为spring源码比较复杂繁多,笔者可能也有理解不到位的地方,欢迎各位指教。