点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

1、什么是循环依赖?

循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方。
A类中有一个B类型的成员变量,需要注入B
B类中有一个A类型的成员变量,需要注入A

2、循环依赖的场景

2.1、构造器的循环依赖【spirng无法解决】

两个循环依赖的类

//A类
public Class A{private B b;pubcli A(B b){this.b=b;}
}
//B类
public Class B{private A a;public B(A a){this. a=a;}}

xml配置信息为

<bean id="a" class="com.make.spring.A"><constructor-arg name="b" ref="b"></constructor-arg>
</bean>
<bean id="b" class="com.make.spring.B"><constructor-arg name="a" ref="a"></constructor-arg>
</bean>

主方法的内容如下

public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConstructor.xml");A bean = context.getBean(A.class);System.out.println(bean);
}

启动报错信息如下:

spring是无法解决构造函数循环依赖注入的,因为这种时候,在实例化A的时候就要获取B的实例化对象,在实例化B的时候要A的实例化对象,所以无法创建任何一个实例。

2.2、setter方法注入属性,singleton单例模式

public class A {private B b;public void setB(B b) {this.b = b;}public B getB() {return b;}
}public class B {private A a;public void setA(A a) {this.a = a;}public A getA() {return a;}
}

xml配置信息

<bean id="a" class="com.make.bean.A"><property name="b" ref="b"></property>
</bean>
<bean id="b" class="com.make.bean.B"><property name="a" ref="a"></property>
</bean>

主方法信息

public static void main(String[] args) {ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");A beanA =context.getBean(A.class);System.out.println(beanA.getB());B beanB=context.getBean(B.class);System.out.println(beanB.getA());
}

最后成功的打印信息

这种情况下,spirng将A的对象实例化后,还未注入属性的A提前缓存起来,也就是提前暴露A,然后让B的实例化过程拿到A来解决依赖注入。

2.3、setter方式,prototype原型模式【spirng无法解决】

两个java类的内容和主方法的内容和1.2的相同

xml配置信息

<bean id="a" class="com.make.bean.A" scope="prototype"><property name="b" ref="b"></property>
</bean>
<bean id="b" class="com.make.bean.B"  scope="prototype"><property name="a" ref="a"></property>
</bean>

最后显示的错误信息如下:

对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。

3、单例setter方法注入—循环依赖解决方法

3.1、使用缓存解决循环依赖

整个spring创建bean对象的步骤主要是如下三三步

然后我们在和创建A对象的时候,注入属性时,需要获取B对象,在注入B的时候获取A对象,会造成循环

那么这个时候他spring提供了一个缓存来解决这种循环的问题

在A对象实例化完后,就先将A对象存入到缓存中暴露出来,让B可以拿到A,拆除循环。
spring的对于解决循环依赖,设置了三级缓存,用来存储不同时期的对象。

3.1、三级缓存

spring的三级循环分别为

 /** 一级缓存* 单例对象缓存:bean name --> bean的完整实例*/private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** 三级缓存* 保存BeanName于创建bean工程之间的缓存:bean name --> 对象工程,lambda表达式*/private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/**  二级缓存* 保存单例对象的半成品:bean name--> 半成品bean(bean实例化好后,没有进行属性填充,没有初始化的半成品对象)*/private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

3.2、代码执行过程示意图

我这里的代码运行过程是按照上面1.2的代码进行说明的。

4、依赖注入具体执行方法

4.1、调用ClassPathXmlApplicationContext的构造方法

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {super(parent);//存储spring配置文件的路径到本地setConfigLocations(configLocations);//判断是否需要需要重新刷新spring容器——ApplicationContextif (refresh) {//刷新spring容器,加载bean的核心方法,刷新spring上下文信息,定义了上下文加载流程——ApplicationContextrefresh();}
}

refresh ApplicationContext,重新刷新Spring容器,注入必要的类、加载bean的一些配置、并实例化bean。
因为AbstractApplicationContext是ClassPathXmlApplicationContext的父类,所以调用的是AbstractApplicationContext的refresh方法

4.2、进入到AbstractApplicationContext类的refresh()方法

@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {/*** 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性到Environment对象中* 5、准备监听器和时间的结合对象,默认为空的集合*/// Prepare this context for refreshing.prepareRefresh();//创建容器对象:DefaultListableBeanFactory//加载xml文件的属性,最终要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//beanFacotry的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);try {//子类覆盖方法做额外的处理,此出我们一般不做任何扩展工作,可以查看web的代码,是有具体实现postProcessBeanFactory(beanFactory);//调用Bean工厂的后置处理器invokeBeanFactoryPostProcessors(beanFactory);//注册BeanPostProcessor 自定义以及spring内部的registerBeanPostProcessors(beanFactory);//  初始化此上下文的消息源initMessageSource();// 初始化事件监听多路广播器initApplicationEventMulticaster();// 留给子类来初始化其他的beanonRefresh();//在所有注册的bean中查找listener bean,注册到消息广播中registerListeners();//初始化剩下的单实例(非懒加载的)finishBeanFactoryInitialization(beanFactory);//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过finishRefresh();}........
}

其中的核心代码为换初始化剩下的单实例(非懒加载的),也就是43行。
是整个spring容器初始化的核心流程。

4.3、进入到finishBeanFactoryInitialization方法

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {......// Instantiate all remaining (non-lazy-init) singletons.//实例化剩下的单例对象beanFactory.preInstantiateSingletons();
}

那么这个方法里面涉及到实例化的就是beanFactory.preInstantiateSingletons();——实例化剩下的单例对象。

由于ConfigurableListableBeanFactory的实现类为DefaultListableBeanFactory,所以之间调用DefaultListableBeanFactory的preInstantiateSingletons方法。

4.4、进入到preInstantiateSingletons方法

@Override
public void preInstantiateSingletons() throws BeansException {if (logger.isDebugEnabled()) {logger.debug("Pre-instantiating singletons in " + this);}//将所有的BeanDefinition的名字创建一个集合,beanNames获取到的是[a,b]List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);//触发所有非延迟加载单例bean的初始化,遍历集合for (String beanName : beanNames) {//合并父类BeanDefinition//Bean定义的公共抽象类是AbstractBeanDefinition,普通的bean在spring加载bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文//所有bean用的AbstractBeanDefintion是RootBeanDefinition,这个时候需要转换一些,将非RootBeanDefinition转成RootBeanDefinition进行后续操作RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//条件判断,抽象,单例,非懒加载if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//判断是否实现了FactoryBean接口if (isFactoryBean(beanName)) {//根据&+beanName来获取具体的对象Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}//如果急切的希望初始化,通过beanName获取bean的实例if (isEagerInit) {getBean(beanName);}}}else {//如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例getBean(beanName);}}}//遍历beanNames,触发所有的SmartInitializingSingleton的后初始化毁掉......
}

这个时候beanNames一共有两个一个是a,一个是b,
那么先获取a。

4.4.1、第一个判断

a不是抽象,也不是懒加载,是单例,所以会走进

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) 

4.4.2、第二个判断

a没有实现FactoryBean接口所以直接执行getBean(a)

if (isFactoryBean(beanName)) {......
}
else {//如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例getBean(beanName);
}

4.5、进入到getBean方法

@Override
public Object getBean(String name) throws BeansException {//此方法获取实际bean的方法,也是触发依赖注入的方法return doGetBean(name, null, null, false);
}

直接调用doGetBean

4.6、进入到dogetBean方法

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//提取对应的beanNamefinal String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.//提前检查单例缓存中是否有手动注册的单例对象,跟循环依赖有关联——6.1Object sharedInstance = getSingleton(beanName);//如果bean的单例对象找到了,且没有创建bean实例时要使用的参数if (sharedInstance != null && args == null) {.....}else {//判断我们是不是正在创建这个实例,如果是失败,应该是在循环参考之内if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}//检查该工厂中是否存在bean定义BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {.....}//如果不是做类型检查,那么就用创建bean,此处在集合中做一个记录if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {//此处做了BeanDefinition对象的转换,当我们从xml文件中加载BeanDefinition对象的时候,封装的对象时GenericBeanDefinition,//此处要做类型转换,如果是子类bean的话,去合并父类的相关属性final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);......// Create bean instance.//创建bean的实例对象,这里都可mdb就是RootBeanDefinition,也就是bean相关的一些定义信息if (mbd.isSingleton()) {//返回以beanName的(原始)单例对象,如果尚未注册,使用singletonFactory创建并注册一个对象sharedInstance = getSingleton(beanName, () -> {try {//为给定的合并后的BeanDefinition(和参数)创建一个bean实例return createBean(beanName, mbd, args);}catch (BeansException ex) {//显示地从单例缓存中删除实例,可能是由创建过程急切地放在那里,以允许循环引用解析,还要删除//接收该bean临时引用的任何bean//销毁给定的bean,如果找到响应的一次性bean实例,委托给destoryBeandestroySingleton(beanName);//重新抛出exthrow ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}......}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}.....return (T) bean;
}

进入到doGetBean,这个时候才是真正获取bean的时候

4.6.1、先尝试从缓存中获取bean——getSingleton(beanName)

 //提前检查单例缓存中是否有手动注册的单例对象
Object sharedInstance = getSingleton(beanName);

具体这块执行的代码是

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {//从单例对象缓存中获取beanName对应的单例对象<<一级缓存>>Object singletonObject = this.singletonObjects.get(beanName);//如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {//如果为空,则锁定全局变量并进行处理synchronized (this.singletonObjects) {//从早期单例对象缓存中获取单例对象(之所以被称为早期单例对象,是因为earlySingletonObjects里// 的所有对象都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)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;
}

这个时候一级缓存是没有a对象的,所以singletonObject获取的为null
然后a也没有在创建过程中,所以直接返回null

4.6.2、开始调用getSingleton(beanName,singleFacotry)

if (mbd.isSingleton()) {//返回以beanName的(原始)单例对象,如果尚未注册,使用singletonFactory创建并注册一个对象sharedInstance = getSingleton(beanName, () -> {try {//为给定的合并后的BeanDefinition(和参数)创建一个bean实例return createBean(beanName, mbd, args);}......});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

这块具体执行的为

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {//如果beanName为null,抛出异常Assert.notNull(beanName, "Bean name must not be null");//使用单实例对象的高速缓冲Map作为锁,保证线程同步synchronized (this.singletonObjects) {//从单例对象的高速缓冲Map中获取beanName对应的单例对象Object singletonObject = this.singletonObjects.get(beanName);//如果获取到的为空if (singletonObject == null) {//如果当前在destorySingletons中if (this.singletonsCurrentlyInDestruction) {......}......//创建单例之前的回调,默认实现将单例注册为当前正在创建中beforeSingletonCreation(beanName);......try {//从单例工厂中获取对象singletonObject = singletonFactory.getObject();//生成了新的单例对象的标记成true,表示生成了新的单例对象newSingleton = true;}......finally {//如果没有抑制异常记录if (recordSuppressedExceptions) {this.suppressedExceptions = null;}//创建单例后的回调,默认实现将单例标记为不在创建中afterSingletonCreation(beanName);}//生成了新的单例对象if (newSingleton) {//将beanName和singletonObject的映射关系添加到该工厂的单例缓存中,也就是一级缓存中addSingleton(beanName, singletonObject);}}return singletonObject;}
}

这个一级缓存获取到的为null,
然后将bean的状态变成创建中,之后调用 singletonFactory.getObject()方法。也就是进入到传给getSingleton方法的lamabda的getBean方法

4.7、进入到getBean方法

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {......try {//实际创建bean的调用Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isDebugEnabled()) {logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}......
}

这里调用真正创建bean的方法,doGetBean

4.8、进入到doGetBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {//这个beanWrapper是用来持有创建出来的Bean对象的BeanWrapper instanceWrapper = null;//获取factoryBean实例缓存if (mbd.isSingleton()) {//如果是单例对象,从factorybean实例缓存中移除当前bean的定义信息instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}//如果实例为空if (instanceWrapper == null) {//实例化bean//根据bean使用对应的策略创建新的实例,如:工厂方法,构造函数主动注入,简单初始化instanceWrapper = createBeanInstance(beanName, mbd, args);}//从包装类中获取原始bean......//运行beanPostProcessor去修改合并的beanDefinition......//缓存单例以便处理循环引用,即使是像BeanFactoryAware这样的生命周期接口触发的boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {......//添加到缓存当中addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}//初始化bean实例Object exposedObject = bean;try {//注入过程populateBean(beanName, mbd, instanceWrapper);// 将会触发postProcessBeforeInitialization和postProcessAfterInitializationexposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {......}......}//注册完成依赖注入的Beantry {registerDisposableBeanIfNecessary(beanName, bean, mbd);}.....return exposedObject;
}

4.8.1、开始调用createBeanInstance(beanName, mbd, args);

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {//解析calssClass<?> beanClass = resolveBeanClass(mbd, beanName);......// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {//判断是否有解析的构造方法或者工厂方法if (mbd.resolvedConstructorOrFactoryMethod != null) {//已经解析过的class构造器resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}//如果解析过if (resolved) {......}//需要根据参数解析、确认构造器的函数(从Bean后处理器确定构造函数)Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 解析的构造器不为空 || 注入类型为构造函数自动注入 || bean定义中有构造器参数 || 传入参数不为空if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||......}// No special handling: simply use no-arg constructor.//使用默认构造器return instantiateBean(beanName, mbd);
}

调用具体的创建bean的方式,有好几种,本例子采用的是//使用默认构造器 return instantiateBean(beanName, mbd); [具体看博客](https://blog.csdn.net/finalcola/article/details/81451019)

4.8.2、将实例化后的a放入到缓存中

判断是否符合需要提前暴露对象,加入缓存的条件

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
  • 目前a单例的

  • allowCircularReferences是允许循环依赖的,这个字段spring默认为true,我们也可以通过改变这个字段,而禁止循环依赖

  • isSingletonCurrentlyInCreation(a),a也是在创建过程中的,在2.3.6的②中已经执行了将a设置为创建中的状态
    均符合要求所以会执行加入缓存的操作

if (earlySingletonExposure) {......//添加到缓存当中addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

加入缓存具体执行的方法为:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");//使用singletonObjects进行加锁,保证线程安全synchronized (this.singletonObjects) {//如果单例对象的高速缓存【Bean名称-bean实例】没有beanName对象if (!this.singletonObjects.containsKey(beanName)) {//将beanName.singletonFactory放入到单例工厂的缓存当中【bean名称-ObjectFactory】this.singletonFactories.put(beanName, singletonFactory);//从早期单例对象的高速缓存【bean名称-bean实例】,移除beanName的相关缓存对象this.earlySingletonObjects.remove(beanName);//将beanName添加到已注册的单例集中this.registeredSingletons.add(beanName);}}
}

下面就该进行到调用populateBean方法为a注入属性

4.9、调用方法populateBean注入属性

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 如果bean实例为空(空实例),并且其属性不为空,则抛出错误,否则跳过......// 在设置属性之前调用Bean的PostProcessor后置处理器if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}}// 依赖注入开始,首先处理autowire自动装配的注入——因为我这里没有使用autowire所以省略......// 检查容器是否持有用于处理单态模式Bean关闭时的后置处理器......if (pvs != null) {//主线// 对属性进行注入操作,解决任何在这个bean工厂运行时其他bean的引用,必须使用深拷贝,所以不会永久修改这个属性applyPropertyValues(beanName, mbd, bw, pvs);}
}

4.9.1、 调用设置xml属性的核心方法applyPropertyValues

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {//如果pvsPropertyValueif (pvs.isEmpty()) {//直接结束方法return;}......List<PropertyValue> deepCopy = new ArrayList<>(original.size());boolean resolveNecessary = false;//遍历属性,将属性转换成对应类的对应属性类型for (PropertyValue pv : original) {//如果该属性已经被解析过if (pv.isConverted()) {//将pv添加到deepCopy中deepCopy.add(pv);}//如果没有else {//获取属性名String propertyName = pv.getName();//获取未经类型转换的值Object originalValue = pv.getValue();//由valueResolver根据pv解析出originalValue所封装的对象Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);......}}......
}

4.9.2、 调用resolveValueIfNecessary方法解决属性的值

@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {//如果values是RuntimeBeanReference实例if (value instanceof RuntimeBeanReference) {//将value强转成RuntimeBeanReference对象RuntimeBeanReference ref = (RuntimeBeanReference) value;//解析出对应的ref所封装的bean元信息(bean名称和类型)的Bean对象//处理引用return resolveReference(argName, ref);}......
}

4.9.3、 调用解决属性的ref外部引用resolveReference方法

@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {try {//定义一个存储b对象的变量Object bean;//获取两一个bean引用的bean类型String refName = ref.getBeanName();refName = String.valueOf(doEvaluate(refName));//如果引用来自父工厂if (ref.isToParent()) {......}else {//获取resolvedName的bean对象bean = this.beanFactory.getBean(refName);//注册beanName与dependentBeanNamed的依赖关系到bean工厂this.beanFactory.registerDependentBean(refName, this.beanName);}if (bean instanceof NullBean) {bean = null;}return bean;}......
}

执行到下面的getBean,就开始获取b

//获取resolvedName的bean对象
bean = this.beanFactory.getBean(refName);

4.10、创建b的过程

  • 创建b的过程会循环前面的4.5—4.9.2,直道注入b的属性时,获取a,也就是运行到4.9.3的getBean(a)开始获取b的属性值a

  • 再次到循环4.5获取a对象,也就是b的属性a的value

  • 这个时候先执行4.6.1的getSingleton方法,这个时候a在一级缓存中没有,但是a是出于创建过程中的,所以可以拿到a
    并将a放入二级缓存,移出三级缓存

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);}
}
  • 从三级缓存中获取到a后,再执行4.6中的真正获取工厂中的a的getObjectForBeanInstance方法

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  • 将拿到的a返回到4.9.3的getBean方法中,a的注入属性完成,之后执行4.8的初始化方法

// 将会触发postProcessBeforeInitialization和postProcessAfterInitialization
exposedObject = initializeBean(beanName, exposedObject, mbd);
  • 将拿到的a返回到4.9.3的getBean方法中,a的注入属性完成,之后执行4.8的初始化方法

// 将会触发postProcessBeforeInitialization和postProcessAfterInitialization
exposedObject = initializeBean(beanName, exposedObject, mbd);
  • b初始化完成后,返回b对象到4.6.2,将b对象放入到一级缓存中

//生成了新的单例对象
if (newSingleton) {//将beanName和singletonObject的映射关系添加到该工厂的单例缓存中,也就是一级缓存中addSingleton(beanName, singletonObject);
}
//addSingleton方法内部执行
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {//将映射关系添加到单例对象的高速缓冲中this.singletonObjects.put(beanName, singletonObject);//移除beanName在三级缓存中的数据——工厂缓存this.singletonFactories.remove(beanName);//移除beanName在二级缓存中的对象this.earlySingletonObjects.remove(beanName);//将beanName添加到已经注册的单例集中this.registeredSingletons.add(beanName);}
}

4.11、将a创建完成

  • b对象创建完成之后,将b对象返回到a的属性注入时获取a的getBean(b)方法,将a类似b注入完成后的过程一样,创建完成a

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:

https://blog.csdn.net/make_1998/article/details/116693232

分布式锁实现,Zookeeper篇

程序员才能看懂的30张图!

MySQL亿级数据分页的奇妙经历

一个update语句让生产数据全变0了

感谢点赞支持下哈 

Spring中循环依赖的解决办法相关推荐

  1. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  2. Spring中循环依赖问题

    1.什么是Spring中的循环依赖 循环依赖就是循环引用,也就是两个或者两个以上的Bean相互持有对方,最终形成闭环.比如A依赖于B,B依赖于C,C又依赖于A. 2.Spring处理循环依赖的机制 无 ...

  3. Spring中循环依赖详解

    目录 一.循环依赖第一种情况 一.示例代码 二.源码分析: 三.debug调试截图 二.循环依赖第二种情况--构造函数 一.示例代码: 二.运行结果: 三.为什么构造函数的循环依赖不被允许? 四.报错 ...

  4. @RequiredArgsConstructor产生循环依赖问题 解决办法

    @RequiredArgsConstructor 该注解是lombok提供的注解,作用是可以使用finanl写法注入bean 但是使用该注解会存在循环依赖的问题 解决方法: 1.改为@Autowire ...

  5. because it is included into a circular dependency循环依赖的解决办法

    一般是Artifacts里面有多个相同的war,war exploded,删掉多余的,留下一个即可  注意:删除多余war,war exploded的时候这里可能爆红 爆出如下异常 Artifact ...

  6. Spring中-IOC-Bean的初始化-循环依赖的解决

    前言 在实际工作中,经常由于设计不佳或者各种因素,导致类之间相互依赖.这些类可能单独使用时不会出问题,但是在使用Spring进行管理的时候可能就会抛出BeanCurrentlyInCreationEx ...

  7. Spring循环依赖及其解决方式

    部分原文链接:java 循环依赖_Java详解之Spring Bean的循环依赖解决方案_以太创服的博客-CSDN博客 1,什么是循环依赖: 在spring中,对象的创建是交给Spring容器去执行的 ...

  8. Spring 循环依赖 以及解决方式

    目录 什么是循环依赖 如何解决循环依赖 两层可不可以? Spring 是如何解决循环依赖问题的_从菜鸟到放弃的博客-CSDN博客_spring 循环依赖怎么解决 什么是循环依赖 多个bean之间相互依 ...

  9. Spring循环依赖以及解决方法

    什么是循环依赖? 循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环.比如A依赖于B,B依赖于C,C又依赖于A. Spring中循环依赖场景有: (1)构造器的循环依 ...

最新文章

  1. 架构师必备技能指南:SaaS(软件即服务)架构设计
  2. python list操作说明
  3. BZOJ 4407 于神之怒加强版
  4. jQuery 判断所有图片加载完成
  5. 前端菜鸟笔记 Day-5 CSS 高级
  6. 相机下载_佳能相机如何连接手机传输相片,视频?
  7. java imap收邮件_android pop3与imap方式接收邮件(javamail)
  8. spring-mvc默认首页配置
  9. 网上购物与开店赢家随身查
  10. 如何删除U盘中的System Volume Information文件夹?
  11. 小米4硬改教程_纯干货!抖音从注册到热门的实操教程分享
  12. いちゃコミュ+~いちゃいちゃコミュニケーション プラス 汉化补丁
  13. python批量读取nc文件_Python读取nc文件的入门级操作
  14. wordpress 安装插件
  15. 5.网页中增加新的内容
  16. TPU中的指令并行和数据并行
  17. 畜牧养殖物联网的应用功能
  18. git clone 出现fatal: unable to access https://github 解决方法
  19. Xshell用Public Key登录华为网络设备(交换机等)
  20. 1到10罗马数字_从罗马到现代

热门文章

  1. 关于Flutter中使用 webview_flutter: 1.0.6 打开公众号连接只显示标题不显示内容的记录
  2. add p4 多个文件_P4_tutorials
  3. 数学规划模型(三):整数规划模型
  4. maximo 入门知识
  5. 天梯赛 L1_001-L1_020 集合
  6. android的adb使用方法,安卓使用adb教程(无root, 亲测)
  7. html 锚文本,什么是锚文本,锚文本链接对SEO的影响!
  8. Xilinx FPGA器件的速度等级
  9. Android开发通知栏的那些事
  10. 程序媛为了万圣节PARTY可谓是别出心裁,她居然cos了一只bug