zoukankan      html  css  js  c++  java
  • spring怎么避免循环依赖

    1、循环依赖

    (1)概念

    对象依赖分为强依赖和弱依赖:

    强依赖指的是一个对象包含了另外一个对象的引用,例如:学生类中包含了课程类,在学生类中存在课程类的引用

    创建课程类:

    @Data
    public class Course {
        private String cname;
        private Integer credit;
    }

    创建学生类:

    @Data
    public class Student {
        private String sname;
        private int age;
        private Course course;
    }

    测试类:

    public class Test {
        public static void main(String[] args) {
            Student student=new Student();
            Course course=new Course();
            student.setCourse(course);
        }
    }

    弱依赖指的是一个对象里面调用了另外一个对象

    循环依赖:A引用B,而B又引用A

    创建课程类,课程类中有学生类的引用:

    @Data
    public class Course {
        private String cname;
        private Integer credit;
        private Student student;
    }

    创建学生类,学生类中存在课程类中的引用:

    @Data
    public class Student {
        private String sname;
        private int age;
        private Course course;
    }

    创建测试类,测试类中学生类调用课程类的对象,课程类的对象又调用学生类的对象:

    public class Test {
        public static void main(String[] args) {
            Student student=new Student();
            Course course=new Course();
            student.setCourse(course);
            course.setStudent(student);
        }
    }

    测试类可以正常地获取对象,也就是说这种方式是支持循环依赖的。

    (2)spring的循环依赖

        <bean id="student" class="com.zhb.bean.Student" scope="singleton">
            <property name="course" ref="course"></property>
        </bean>
        <bean id="course" class="com.zhb.bean.Course" scope="singleton">
            <property name="student" ref="student"></property>
        </bean>

    单例模式下支持,多例模式下不支持

    (3)spring是否支持循环依赖

    支持

    (4)spring的所有对象是不是都支持循环依赖

    单例模式下支持:单例模式下是首先创建出两个对象,然后进行依赖的注入。A注入B,B注入A。

    多例模式下不支持:A创建的时候会去判断是否依赖于其他对象,如果依赖的话就不会去先创建A。创建B的时候也会去判断是否依赖其他对象,如果A依赖于B,而B又依赖于A的话就会造成一个死循环,两个对象都不会创建。

    2、spring循环依赖的过程

    (1)流程

     

     (2)源码

    ClassPathXmlApplicationContext方法:

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
            super(parent);
            this.setConfigLocations(configLocations);
            if (refresh) {
                this.refresh();//refresh方法是真正的创建对象的方法
            }
    
        }

    refresh方法:

    public void refresh() throws BeansException, IllegalStateException {
            synchronized(this.startupShutdownMonitor) {
                this.prepareRefresh();
                ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
                this.prepareBeanFactory(beanFactory);
    
                try {
                    this.postProcessBeanFactory(beanFactory);
                    this.invokeBeanFactoryPostProcessors(beanFactory);//Bean工厂的后置处理器
                    this.registerBeanPostProcessors(beanFactory);
                    this.initMessageSource();
                    this.initApplicationEventMulticaster();
                    this.onRefresh();
                    this.registerListeners();
                    this.finishBeanFactoryInitialization(beanFactory);//此方法是真正的创建对象的方法,能够实例化所有的单例bean
                    this.finishRefresh();
                } catch (BeansException var9) {
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                    }
    
                    this.destroyBeans();
                    this.cancelRefresh(var9);
                    throw var9;
                } finally {
                    this.resetCommonCaches();
                }
    
            }
        }

    finishBeanFactoryInitialization

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
            if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
                beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
            }
    
            if (!beanFactory.hasEmbeddedValueResolver()) {
                beanFactory.addEmbeddedValueResolver((strVal) -> {
                    return this.getEnvironment().resolvePlaceholders(strVal);
                });
            }
    
            String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
            String[] var3 = weaverAwareNames;
            int var4 = weaverAwareNames.length;
    
            for(int var5 = 0; var5 < var4; ++var5) {
                String weaverAwareName = var3[var5];
                this.getBean(weaverAwareName);
            }
    
            beanFactory.setTempClassLoader((ClassLoader)null);
            beanFactory.freezeConfiguration();
            beanFactory.preInstantiateSingletons();
        }

     接口:

    void preInstantiateSingletons() throws BeansException;
    public void preInstantiateSingletons() throws BeansException {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Pre-instantiating singletons in " + this);
            }
    
            List<String> beanNames = new ArrayList(this.beanDefinitionNames);
            Iterator var2 = beanNames.iterator();//取出名字
    
            while(true) {
                String beanName;
                Object bean;
                do {
                    while(true) {
                        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) {
                                                SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
                                                if (System.getSecurityManager() != null) {
                                                    AccessController.doPrivileged(() -> {
                                                        smartSingleton.afterSingletonsInstantiated();
                                                        return null;
                                                    }, this.getAccessControlContext());
                                                } else {
                                                    smartSingleton.afterSingletonsInstantiated();
                                                }
                                            }
                                        }
    
                                        return;
                                    }
    
                                    beanName = (String)var2.next();
                                    bd = this.getMergedLocalBeanDefinition(beanName);
                                } while(bd.isAbstract());//单例抽象懒加载
                            } while(!bd.isSingleton());
                        } while(bd.isLazyInit());
    
                        if (this.isFactoryBean(beanName)) {
                            bean = this.getBean("&" + beanName);
                            break;
                        }
    
                        this.getBean(beanName);
                    }
                } while(!(bean instanceof FactoryBean));
    
                FactoryBean<?> factory = (FactoryBean)bean;
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    SmartFactoryBean var10000 = (SmartFactoryBean)factory;
                    ((SmartFactoryBean)factory).getClass();
                    isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext());
                } else {
                    isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
                }
    
                if (isEagerInit) {
                    this.getBean(beanName);
                }
            }
        }

    getSingleton方法:

     @Nullable
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName);//
            if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
                synchronized(this.singletonObjects) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null && allowEarlyReference) {
                        ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
    
            return singletonObject;
        }

    3、怎么避免循环依赖?

    三级缓存

    • 一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
    • 二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean
    • 三级缓存:singletonFactories,三级缓存,存放实例化完成的Bean工厂。

    假设A依赖B,B依赖A(注意:这里是set属性依赖)分以下步骤执行:

      A依次执行doGetBean、查询缓存、createBean创建实例,实例化完成放入三级缓存singletonFactories中,接着执行populateBean方法装配属性,但是发现有一个属性是B的对象。因此再次调用doGetBean方法创建B的实例,依次执行doGetBean、查询缓存、createBean创建实例,实例化完成之后放入三级缓存singletonFactories中,执行populateBean装配属性,但是此时发现有一个属性是A对象。

      因此再次调用doGetBean创建A的实例,但是执行到getSingleton查询缓存的时候,从三级缓存中查询到了A的实例(早期引用,未完成属性装配),此时直接返回A,不用执行后续的流程创建A了,那么B就完成了属性装配,此时是一个完整的对象放入到一级缓存singletonObjects中。

      B创建完成了,则A自然完成了属性装配,也创建完成放入了一级缓存singletonObjects中。

    每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛
  • 相关阅读:
    双系统安装,引导被覆盖-如何解决?
    关于apue.3e中apue.h的使用
    UML类图关系
    设计模式的原则
    插入排序Insertion Sort
    Xcode intellisense meaning of letters in colored boxes like f,T,C,M,P,C,K,# etc
    asp.net mvc 页面内容呈现Html.Raw HtmlString
    sqlserver通过设计器修改表结构保存时提示:保存到文本问题
    在windows下使用Cygwin模拟unix环境,并安装apt-cyg,svn等工具
    vs2015插件推荐 Productivity Power Tools 2015
  • 原文地址:https://www.cnblogs.com/zhai1997/p/13568343.html
Copyright © 2011-2022 走看看