zoukankan      html  css  js  c++  java
  • SpringIOC——DI循环依赖

    要弄清楚循环依赖

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

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

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

    2、DefaultSingletonBeanRegistry类中的5个容器(补充:很多地方说的三级缓存就是下面的 1/2/3容器)

        /** 记录已将创建的单例<beanName,singletonBean> */
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
        /** 记录singletonFactory<beanName,singletonFactory> singeletonFactory中存放beanName和上面的①阶段的bean:Bean实例化实例对象(还未初始化DI)*/
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
        /** 记录早期的singletonBean 存放的也是① */
        private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    
        /** 存放已经初始化后的beanName,有序 */
        private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
    
        /** 记录正在初始化的bean的beanName */
        private final Set<String> 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); ... } }

    ② 上面singletonObject = 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> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
            ...
            //假设A、B互相依赖
            //第一次getBean(A),sharedInstance == null(一级缓存singletonObjects中没有),bean还未被初始化,走else,createBean初始化bean
            //A打标:正在创建中,代码在①中beforeSingletonCreation()中,,主要逻辑:放入到singetonsCurrentlyInCreation这个Set中
    //A实例化(早期Bean)后保存到singletonFactories中②中addSingletonFactory(beanName,singletonFactory)(即三级缓存)
    //DI依赖注入:②中populateBean(beanName,mbd,instanceWrapper),发现依赖B,调用getBean(B)初始化B的单例
    //调用getBean(B)重复上面步骤,DI依赖注入发现依赖A,调用getBean(A)
    //第二次getBean(A),一级缓存singletonObjects中依然没有初始化完成的Bean,singleObject == null
    //③中if(singletonObject == null && isSingletonCurrentlyInCreation(A))由于打标了所以返回上面创建的早期Bean-A(具体是先访问二级缓存earlySingletonObjects,再访问三级缓存singletonFactories)
    //下面if条件直接返回bean,没有走else破坏了循环
    Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // bean = getObjectForBeanInstance(sharedInstance, 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;
  • 相关阅读:
    MySQL--06
    MySQL--05
    MySQL--04
    MySQL--03
    MySQL--02
    MySQL--01
    JavaScript3
    JavaScript2
    四大函数式接口 函数型接口 断定型接口 消费型接口 供给型接口 流式计算
    课后作业-阅读任务-阅读提问-4
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12388072.html
Copyright © 2011-2022 走看看