千家信息网

如何用spring源码剖析spring bean循环依赖

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,本篇文章给大家分享的是有关如何用spring源码剖析spring bean循环依赖,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。spri
千家信息网最后更新 2025年02月02日如何用spring源码剖析spring bean循环依赖

本篇文章给大家分享的是有关如何用spring源码剖析spring bean循环依赖,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

spring bean循环依赖

spring bean循环依赖应该是spring 源码中比较难的一块知识了,下面我们结合代码还有时序图,来进行分析,看下spring 是如何优雅的处理spring bean的循环依赖的。

什么是bean的循环依赖

我们都知道spring的IOC 和DI,它可以帮助我们创建对象,并且可以帮我们自动注入需要spring管理的对象。然后会存在一种这样的情况,在对象 A 中需要依赖 B,而在对象 B 中有又依赖 A,当然可以有更多的对象依赖,他们之间会组成了一个闭环,如下图 在spring 初始化bean A的时候发现bean A依赖于bean B,然后去实例化bean B,实例化bean B的时候又发现bean B依赖于bean A...,这样陷入了一个无限循环的过程中,最终可能会导致内存溢出。当然,这只是我们的一个设想,spring当然不会让这样的事情发生。spring提供一个很优雅的方式来帮我们解决了bean之间循环依赖的问题,通过引入三级缓存机制来解决。 另外再说一点,不是所有的循环依赖spring 都可以解决,以下两种方式spring也是无法解决的

  • 依赖是通过构造方法实现的

  • scope 为prototype,也就是原型的情况

在正式开始之前,我们再说下spring的三级缓存以及定义 先来看下代码中是如何定义的

     /** Cache of singleton objects: bean name to bean instance. */        private final Map singletonObjects = new ConcurrentHashMap<>(256);        /** Cache of singleton factories: bean name to ObjectFactory. */        private final Map> singletonFactories = new HashMap<>(16);        /** Cache of early singleton objects: bean name to bean instance. */        private final Map earlySingletonObjects = new HashMap<>(16);
  • singletonObjects 一级缓存, 用于存放完全初始化之后的bean,也就是说,所有的准备工作已经完成了,可以拿出来使用了

  • earlySingletonObjects 二级缓存,存放原始的bean对象,这时候bean只是实例化完成,还没有进行属性设置等工作

  • singletonFactories 三级缓存,存放只是实例化,还没有进行其它任何操作的bean对象

下面我们结合代码来做进一步的分析

依赖代码

bean A

创建类BeanA,然后通过set注入BeanB

public class BeanA {        private BeanB beanB;        public void setBeanB(BeanB beanB) {                this.beanB = beanB;        }}

bean B

创建类BeanB,然后通过set注入BeanA

public class BeanB {        private BeanA beanA;        public void setBeanA(BeanA beanA) {                this.beanA = beanA;        }}

配置文件applicationContext.xml

将BeanA 和BeanB 交给spring来进行管理

                                                                        

测试代码

使用ClassPathXmlApplicationContext来初始化bean

public class BeanTest {        public static void main(String[] args) {                ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");                Object beanA = applicationContext.getBean("beanA");                System.out.println(beanA);        }}

源码分析

循环依赖时序图

在分析源码前我们先来看下spring 循环依赖的时序图,对于后面我们分析源码会有很大的帮助 原始文件可以从这里下载

ClassPathXmlApplicationContext.java

我们调用了ClassPathXmlApplicationContext的带参构造方法,最终调用了下面的构造。这里完成了三件事:

  1. super(parent)初始化父类

  2. setConfigLocations(configLocations)设置本地的配置信息

  3. refresh()完成spring容器的初始化

这里我们重点观察第三个方法,因为spring bean的初始化是在这里完成的

        public ClassPathXmlApplicationContext(                        String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)                        throws BeansException {                // 初始化父类                super(parent);                // 设置本地的配置信息                setConfigLocations(configLocations);                // 完成Spring容器的初始化                if (refresh) {                        refresh();                }        }

AbstractApplicationContext.java

上面说了,refresh方法是初始化spring容器的,所以这是一个核心方法。这里面包含beanFactory 和bean的初始化操作,因为方法比较多,对每个方法都进行了注释,不一一赘述了,这里我们重点关注finishBeanFactoryInitialization(),这个方法做了一下操作

  • 初始化所有剩下的非懒加载的单例bean

  • 初始化创建非懒加载方式的单例Bean实例(未设置属性)

  • 填充属性

  • 初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)

  • 调用BeanPostProcessor(后置处理器)对实例bean进行后置处理 所以我们接下来看下这个方法

public void refresh() throws BeansException, IllegalStateException {                // 对象锁加锁                synchronized (this.startupShutdownMonitor) {                        //刷新前的预处理,表示在真正做refresh操作之前需要准备做的事情:                        prepareRefresh();                        /*                           获取BeanFactory;默认实现是DefaultListableBeanFactory                加载BeanDefition 并注册到 BeanDefitionRegistry                         */                        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();                        //BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)                        prepareBeanFactory(beanFactory);                        try {                                //BeanFactory准备工作完成后进行的后置处理工作                                postProcessBeanFactory(beanFactory);                                //实例化实现了BeanFactoryPostProcessor接口的Bean,并调用接口方法                                invokeBeanFactoryPostProcessors(beanFactory);                                //注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行                                registerBeanPostProcessors(beanFactory);                                //初始化MessageSource组件(做国际化功能;消息绑定,消息解析);                                initMessageSource();                                //初始化事件派发器                                initApplicationEventMulticaster();                                //子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器                                onRefresh();                                //注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean                                registerListeners();                                /*  Instantiate all remaining (non-lazy-init) singletons.                                        初始化所有剩下的非懒加载的单例bean                                        初始化创建非懒加载方式的单例Bean实例(未设置属性)                    填充属性                    初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)                    调用BeanPostProcessor(后置处理器)对实例bean进行后置处理                                 */                                finishBeanFactoryInitialization(beanFactory);                                //完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)                                finishRefresh();                        } catch (BeansException ex) {                                destroyBeans();                                cancelRefresh(ex);                                throw ex;                        } finally {                                resetCommonCaches();                        }                }        }

这个方法的最后调用了beanFactory的preInstantiateSingletons()方法,接下继续跟踪preInstantiateSingletons()方法

      protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {                if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&                                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {                        beanFactory.setConversionService(                                        beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));                }                if (!beanFactory.hasEmbeddedValueResolver()) {                        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));                }                // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.                String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);                for (String weaverAwareName : weaverAwareNames) {                        getBean(weaverAwareName);                }                // Stop using the temporary ClassLoader for type matching.                beanFactory.setTempClassLoader(null);                // Allow for caching all bean definition metadata, not expecting further changes.                beanFactory.freezeConfiguration();                // Instantiate all remaining (non-lazy-init) singletons.                // 实例化所有立即加载的单例bean                beanFactory.preInstantiateSingletons();        }

DefaultListableBeanFactory.java

preInstantiateSingletons()中获取了所有需要spring管理的bean的name,然后需要遍历,进行bean的创建,核心方法是getBean(beanName),根据获取到的bean name进行bean的初始化,所以接下来我们跟踪getBean(beanName)

public void preInstantiateSingletons() throws BeansException {                if (logger.isTraceEnabled()) {                        logger.trace("Pre-instantiating singletons in " + this);                }                // 获取所有bean的名字                List beanNames = new ArrayList<>(this.beanDefinitionNames);                // 触发所有非延迟加载单例bean的初始化,主要步骤为getBean                for (String beanName : beanNames) {                        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);                        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {                                if (isFactoryBean(beanName)) {                                        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);                                        // 如果是FactoryBean则加&                                        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);                                }                        }                }                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();                                }                        }                }        }

开始处理循环依赖

为了方便阅读删除了部分源码

上面方法中调用了getBean()getBean()又调用了doGetBean(),经过前面的铺垫,其实到这里,才开始了真正的循环依赖相关的源码逻辑。 之前我们说过spring 的三级缓存,这里根据bean name先调用getSingleton(beanName)方法,getSingleton(beanName)方法中又调用了它的重载方法。我们先假设要去找的bean为beanA,spring先从一级缓存中去找我们要的beanA,找不到的话去二级缓存中去找,二级缓存还找不到去一级缓存中去拿,当然,因为刚加载,所以三级缓存中也是没有的。所以代码继续往下执行。

  public Object getBean(String name) throws BeansException {                return doGetBean(name, null, null, false);        }protected  T doGetBean(final String name, @Nullable final Class requiredType,                        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {                // 解析beanName 如果以&开头去掉&开头,如果是别名获取到真正的名字                final String beanName = transformedBeanName(name);                // 尝试从一二三级缓存中获取 bean                Object sharedInstance = getSingleton(beanName);                // 如果已经存在则返回                if (sharedInstance != null && args == null) {                        // 针对 FactoryBean 的处理                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);                } else {                        // 如果是prototype类型且开启允许循环依赖,则抛出异常                        if (isPrototypeCurrentlyInCreation(beanName)) {                                throw new BeanCurrentlyInCreationException(beanName);                        }                        try {                                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName)                                // 创建单例bean                                if (mbd.isSingleton()) {                                        sharedInstance = getSingleton(beanName, () -> {                                                try {                                                        // 创建 bean                                                        return createBean(beanName, mbd, args);                                                }                                                catch (BeansException ex) {                                                        destroySingleton(beanName);                                                        throw ex;                                                }                                        });                                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);                                }                        }                }                return (T) bean;        }        public Object getSingleton(String beanName) {                return getSingleton(beanName, true);        }                protected Object getSingleton(String beanName, boolean allowEarlyReference) {                //先从一级缓存singletonObjects中拿                Object singletonObject = this.singletonObjects.get(beanName);                // isSingletonCurrentlyInCreation(beanName)判断当前单例bean是否正在创建中                if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {                        synchronized (this.singletonObjects) {                                //一级缓存没有从二级缓存earlySingletonObjects中去拿                                singletonObject = this.earlySingletonObjects.get(beanName);                                if (singletonObject == null && allowEarlyReference) {                                        //二级缓存没有从三级缓存singletonFactories去拿                                        ObjectFactory singletonFactory = this.singletonFactories.get(beanName);                                        if (singletonFactory != null) {                                                singletonObject = singletonFactory.getObject();                                                //三级缓存中有的话放入二级缓存中,同时从一级缓存中删除                                                this.earlySingletonObjects.put(beanName, singletonObject);                                                this.singletonFactories.remove(beanName);                                        }                                }                        }                }                return singletonObject;        }       

接着上面的doGetBean()方法往下走,又调用了getSingleton()的另一个重载方法,可以看到第二个参数是一个ObjectFactory接口,而这里spring采用了一个lambda表达式来实现了getObject()方法。调用传进来的lambda表达式singletonFactory.getObject(),进行bean的创建。

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {                Assert.notNull(beanName, "Bean name must not be null");                synchronized (this.singletonObjects) {                        Object singletonObject = this.singletonObjects.get(beanName);                        if (singletonObject == null) {                                // 是否正在销毁,异常                                if (this.singletonsCurrentlyInDestruction) {                                        throw new BeanCreationNotAllowedException(beanName,                                                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +                                                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");                                }                                if (logger.isDebugEnabled()) {                                        logger.debug("Creating shared instance of singleton bean '" + beanName + "'");                                }                                // 验证完要真正开始创建对象,先标识该bean正在被创建,因为spingbean创建过程复杂,步骤很多,需要标识                                beforeSingletonCreation(beanName);                                boolean newSingleton = false;                                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);                                if (recordSuppressedExceptions) {                                        this.suppressedExceptions = new LinkedHashSet<>();                                }                                try {                                        // 传进来的调用,lamda表达式使用                                        singletonObject = singletonFactory.getObject();                                        newSingleton = true;                                }                                catch (IllegalStateException ex) {                                        // Has the singleton object implicitly appeared in the meantime ->                                        // if yes, proceed with it since the exception indicates that state.                                        singletonObject = this.singletonObjects.get(beanName);                                        if (singletonObject == null) {                                                throw ex;                                        }                                }                                catch (BeanCreationException ex) {                                        if (recordSuppressedExceptions) {                                                for (Exception suppressedException : this.suppressedExceptions) {                                                        ex.addRelatedCause(suppressedException);                                                }                                        }                                        throw ex;                                }                                finally {                                        if (recordSuppressedExceptions) {                                                this.suppressedExceptions = null;                                        }                                        afterSingletonCreation(beanName);                                }                                if (newSingleton) {                                        addSingleton(beanName, singletonObject);                                }                        }                        return singletonObject;                }        }

接下来看下lambda表达式中的createBean(beanName, mbd, args)方法是如何实现的 createBean()中其实又调用了doCreateBean(),它才是真正干活的。这里首先调用对createBeanInstance(beanName, mbd, args)beanA进行实例化,然后放入三级缓存中,接下来调用populateBean(beanName, mbd, instanceWrapper)beanA进行属性填充,在我们这里其实就是填充beanB,我们继续看填充方法中做了什么

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {                // 拿到Bd                RootBeanDefinition mbdToUse = mbd;                //....                try {                        // 进入,真真正正创建bean                        Object beanInstance = doCreateBean(beanName, mbdToUse, args);                        if (logger.isTraceEnabled()) {                                logger.trace("Finished creating instance of bean '" + beanName + "'");                        }                        return beanInstance;                } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {                        throw ex;                }        }protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {                // Instantiate the bean.                BeanWrapper instanceWrapper = null;                if (mbd.isSingleton()) {                        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);                }                if (instanceWrapper == null) {                        // 创建 Bean 实例,仅仅调用构造方法,但是尚未设置属性                        instanceWrapper = createBeanInstance(beanName, mbd, args);                }                        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&                                isSingletonCurrentlyInCreation(beanName));                if (earlySingletonExposure) {                        if (logger.isTraceEnabled()) {                                logger.trace("Eagerly caching bean '" + beanName +                                                "' to allow for resolving potential circular references");                        }                        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));                }                //...                Object exposedObject = bean;                try {                        // Bean属性填充                        populateBean(beanName, mbd, instanceWrapper);                        // 调用初始化方法,应用BeanPostProcessor后置处理器                        exposedObject = initializeBean(beanName, exposedObject, mbd);                }                //...                return exposedObject;        }

populateBean()中最后调用了applyPropertyValues(beanName, mbd, bw, pvs)applyPropertyValues(beanName, mbd, bw, pvs)方法中有调用了resolveValueIfNecessary(pv, originalValue)resolveValueIfNecessary(pv, originalValue)中又调用了resolveReference(argName, ref),好了终于到重要关头了,在resolveReference(argName, ref)中我们可用看到,又调用了getBean(refName)方法,获取beanB。呀,这是什么情况,怎么又回到起点了?哈哈,别着急,我们继续分析。 既然调用了getBean()方法,我们不妨在回头看看(代码我就不再贴一遍了)。 getBean()继续调用doGetBean()方法,然后继续调用getSingleton()方法去缓存中拿beanB,然后发现beanB也不再缓存中,然后就开始去创建beanB。创建beanB先进行实例化,然后放入到缓存中,之后再调用populateBean()进行属性填充(其实就是填充依赖beanA),之前我们提到beanA,在实例化beanB之前已经实例化完成并放入到三级缓存中了,这里我们就可以使用了,虽然还是个娃娃,但是够用了。到这里beanB属性填充之后就可以长大,成为完成的bean了。这时候将beanB放入到缓存池中,我们就可以回过头来填充beanA的属性了。到这里 ,beanAbeanB就完成了他们整个bean的创建过程了。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {        //...        if (pvs != null) {                applyPropertyValues(beanName, mbd, bw, pvs);        }}protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {                //...                for (PropertyValue pv : original) {                        if (pv.isConverted()) {                                deepCopy.add(pv);                        } else {                                String propertyName = pv.getName();                                Object originalValue = pv.getValue();                                //                                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);                                Object convertedValue = resolvedValue;                                //...                        }                }                //...        }public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {                if (value instanceof RuntimeBeanReference) {                        RuntimeBeanReference ref = (RuntimeBeanReference) value;                        return resolveReference(argName, ref);                }                //...        }        private Object resolveReference(Object argName, RuntimeBeanReference ref) {                try {                        Object bean;                        String refName = ref.getBeanName();                        refName = String.valueOf(doEvaluate(refName));                        if (ref.isToParent()) {                                bean = this.beanFactory.getParentBeanFactory().getBean(refName);                        }                        else {                                bean = this.beanFactory.getBean(refName);                                this.beanFactory.registerDependentBean(refName, this.beanName);                        }                        if (bean instanceof NullBean) {                                bean = null;                        }                        return bean;                }                catch (BeansException ex) {}     

以上就是如何用spring源码剖析spring bean循环依赖,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

0