SpringIOC DI循环依赖实例详解

网友投稿 548 2023-06-20

SpringIOC DI循环依赖实例详解

SpringIOC DI循环依赖实例详解

要弄清楚循环依赖

1、需要知道Bean初始化的两个阶段

① Bean实例化创建实例对象(new Bean())

② Bean实例对象初始化(DI:注解自动注入)

2、DefaultSingletonBeanRegistry类中的5个容器

/** 记录已将创建的单例 */

private final Map singletonObjects = new ConcurrentHashMap<>(256);

/** 记录singletonFactory singeletonFactory中存放beanName和上面的①阶段的bean:Bean实例化实例对象(还未初始化DI)*/

private final Map> singletonFactories = new HashMap<>(16);

/** 记录早期的singletonBean 存放的也是① */

private final Map earlySingletonObjects = new HashMap<>(16);

/** 存放已经初始化后的beanName,有序 */

private final Set registeredSingletons = new LinkedHashSet<>(256);

/** 记录正在初始化的bean的beanName */

private final Set singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

其中跟循环依赖相关的是singletonFactories、singeletonsCurrentlyInCreation、earlysingletonObjects.

3、循环依赖实现

①bean初始化前后会打标,加入到singletonsCurrentlyInCreation容器中,这个打标会在核心方法getSingleton()中起作用

/* org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory>) */

public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {

...

//循环依赖相关:初始化前先singletonsCurrentlyInCreation.add(beanName)

beforeSingletonCreation(beanName);

...

//lamda表达式:其实是调用createBean(beanName, mbd, args):Bean初始化

singletonObject = singletonFactory.getObject();

...

//循环依赖相关:初始化后singletonsCurrentlyInCreation.remove(beanName)

afterSingletonCreation(beanName);

...//初始化完后

//this.singletonObjects.put(beanName, singletonObject);放入到单例容器中

//this.singletonFactories.remove(beanName);清空循环依赖的两个打标

//this.earlySingletonObjects.remove(beanName);

//this.registeredSingletons.add(beanName);放入单例beanName容器中

addSingleton(beanName, singletonObject);

...

}

}

② 上面singlehttp://tonObject = singletonFactory.getObject()时向singletonFactories中记录了(new Bean()),singletonFactories也会在核心方法getSingleton()中起作用

/* org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean */

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

throws BeanCreationException {

...

//循环依赖相关逻辑:

//this.singletonFactories.put(beanName, singletonFactory);

//将实例化bean(①阶段)、beanName组装成singletonFactory装入singletonFactories容器

//this.earlySingletonObjects.remove(beanName);

//删除earlySingletonObjects中beanName

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

...

//实例初始化 就是在这里面实现依赖注入DI的:反射实现

//调用AutowiredAnnotationBeanPostProcessor.postProcessProperties

populateBean(beanName, mbd, instanceWrapper);

...

}

③ 核心方法getSingleton

/* org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) */

protected Object getSingleton(String beanName, boolean allowEarlyReference) {

Object singletonObject = this.singletonObjects.get(beanName);

     //循环依赖核心就在于这个判断,由于打标+记录了①阶段的bean,

//循环依赖第二次调用getBean("a")时,这里会直接返回第一次调用getBean("a")创建的①阶段的bean

//而不会调用createBean("a")再次bean初始化(造成两个bean的循环创建)

if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {

synchronized (this.singletonObjects) {

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;

}

④ 循环依赖流程

/* org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean */

protected T doGetBean(final String name, @Nullable final Class requiredType,

@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

...

//假设A、B互相依赖

//第一次getBean(A),sharedInstance == null,走else,createBean

//A正在创建打标,①中beforeSingletonCreation()

//A实例化后保存到singletonFactories中②中addSingletonFactory(beanName,singletonFactory)

//DI依赖注入:②中populateBean(beanName,mbd,instanceWrapper),发现依赖B,调用getBean(B)初始化B的单例

//调用getBean(B)重复上面步骤,DI依赖注入发现依赖A,调用getBean(A)

//第二次getBean(A),③中if(singletonObject == null && isSingletonCurrentlyInCreation(A))由于打标了所以返回singleFactory.getObject()

//下面if条件直接返回bean,没有走else破坏了循环

Object sharedInstance = getSingleton(beanName);

if (sharedInstance != null && args == null) {

//

bean = getObjectForBeanInstance(sharehttp://dInstance, name, beanName, null);

}

else {

...

//

createBean(beanName, mbd, args);

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

}

return bean;

}

四、总结

未看源码之前,其实对循环依赖有一个想法:循环依赖可以看做是一个死锁。

预防死锁的方法:打破死锁的四个必要条件(互斥、请求并等待、不可剥夺、循环等待),由于循环依赖的资源是对象自身,所以常用破坏循环等待条件方法:编号顺序执行,不适用

选择破坏请求并等待条件:先创建对象,再赋值,模型

A a = new A();

B b = new B();

A.b = b;

B.a = a;

研究源码之后发现:想法差不多,但是代码实现非常精彩。模型(打标没想到过)

A a = new A();

B b = new B();

b.a = a;

a.b = b;

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:配置Servlet两种方法以及特点详解
下一篇:SpringMVC DispatcherServlet组件实现解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~