spring IOC之循环依赖

使用过spring的人,肯定知道spring的IOC,DI。那么在我们使用的过程中,可能会出现比如我一个A类,里面注入了B类,而B类,里面又注入了A类
如下图所示:

@Component
public class DemoA {
    @Autowired
    DemoB demoB;

    public DemoA() {
    }
}
@Component
public class DemoB {
    @Autowired
    DemoA demoA;

    public DemoB() {
    }
}

后来发现项目是正常启动的。
但是如果我们在构造函数里面去进行循环依赖呢

@Component
public class DemoA {

    public DemoA(DemoB demoB) {
    }

}
@Component
public class DemoB {

    public DemoB(DemoA demoA) {
    }


}

启动时就会报循环引用的问题

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoA' defined in file [/Users/nanjunbo/Documents/Ideaproject/demoSpring/target/classes/demoIoc/DemoA.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoB' defined in file [/Users/nanjunbo/Documents/Ideaproject/demoSpring/target/classes/demoIoc/DemoB.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'demoA': Requested bean is currently in creation: Is there an unresolvable circular reference?

那这到底是为什么呢?这里就需要知道spring创建bean的时候到底做了什么。
1.首先我们需要知道bean到底是什么?根据spring官方文档的描述,bean是一个由Spring IoC容器实例化、组装和管理的对象。那么原生java对象,跟你用spring来创建一个bean到底有什么区别。其实在创建bean的过程中,对java的原生对做了一系列的处理,扩展。这个就是bean的生命周期。
现在我们从代码看看spring的生命周期。
先看一下测试类:

public class Test {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext abstractApplicationContext = new AnnotationConfigApplicationContext();
        abstractApplicationContext.register(DemoConfig.class);
        abstractApplicationContext.refresh();
        System.out.println(abstractApplicationContext.getBean("demoA"));

    }
}

可以看到将测试的配置文件注册进容器中,然后刷新容器,就可以获取bean了。
那refresh到底做了什么呢?

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //使用对象锁,对spring容器的refresh跟destroy进行加锁
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //准备刷新容器前的环境
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            //对beanFactory进行赋值
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                //提供一个修改beanFactory的入口
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                //同样是对beanFactory进行修改
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                //注册bean创建时的拦截器
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                //初始化MessageSource
                initMessageSource();

                // Initialize event multicaster for this context.
                //初始化事件的上下文广播
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                //空方法,可以自己定义想处理什么
                onRefresh();

                // Check for listener beans and register them.
                //注册监听器
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //(重要)完成bean的初始换
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }
public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        List beanNames = new ArrayList<>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) {
            //把非RootBeanDefinition的merge成RootBeanDefinition
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //判断是否需要实例化bean
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {
                    //获取factoryBean
                    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)
                                            ((SmartFactoryBean) factory)::isEagerInit,
                                    getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);
                        }
                    }
                }
                else {
                    //获取普通Bean(核心方法)
                    getBean(beanName);
                }
            }
        }

        // Trigger post-initialization callback for all applicable beans...
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged((PrivilegedAction) () -> {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

然后主要看doGetBean的方法,然后有一段doCreateBean的方法。
初始化bean的时候,将其放入singletonFactories中,然后调用populateBean方法,来注入属性,如果这时候发生了依赖,比如文章开头的示例,初始化A的时候,注入了B,然后再初始化B,发现又注入了A。这时候初始化B,然后调用populateBean方法时,然后又去getBean(A),去getBean的时候,从singletonFactories中获取,然后就发现了有A的存在,不用再去实例化A了
这里只是大概写了一下,spring的源码太多了,太吊了。只要对大概的流程知道就行了。每一句每一句分析需要消耗大量的时间,不过对个人的成长很有用

你可能感兴趣的:(spring IOC之循环依赖)