美文网首页
最易懂Spring循环依赖

最易懂Spring循环依赖

作者: 分布式与微服务 | 来源:发表于2022-07-06 09:08 被阅读0次
image.png

前言

了解Spring循环依赖和三级缓存需要熟悉IOCAOP流程。

工作中常用new语句创建对象,通过new方法创建的对象是没有属性填充的,而Spring创建对象时可指定对象的生命周期;

说Spring的bean默认是单例的是因为Spring启动时只会生成单例对象放入单例池,即singletonBeanRegistry,而使用@Scope("prototype")注解标注的类是不会加载进单例池中的。

不理解spring注入方式的同学可以先看往期这篇:[Spring Dependency Injection]

观看本篇需要熟悉getBean流程:[ 简单理解Spring getBean流程]

介绍

循环依赖就是循环引用,指两个或则两个以上的bean互相依赖对方,最终形成闭环。比如“A对象依赖B对象,而B对象也依赖A对象”。

SpringIOC中分为两种情况

  1. 普通的Bean死循环创建
  2. 创建的Bean被AOP代理

Spring解决循环依赖的前提:

  1. 只支持单例对象。原型prototype的场景如果循环依赖就会造成无限套娃,所以是不被支持的,spring会抛出异常。 我们谈的循环依赖都是依据单例对象相互依赖产生的循环依赖问题。

  2. 不支持构造构造器注入的循环依赖(这里说的是A、B对象均采用构造方法注入)。

熟悉依赖注入方式的应该清楚,构造器注入是通过构造方法来生成对象,其必须要先获取属性,才能生成调用构造方法进行实例化,这种情况的循环依赖是无法解决的。

属性注入和setter注入时是需要使用autowried的,而构造器注入是不需要的。

熟悉autowried底层应该清楚,autowired是在实例化后、初始化完成前调用后置处理器从IOC容器中拿到bean通过反射来为对象属性赋值的。

网上找了一张图来说明A、B对象依赖注入方式不同时spring能否解决循环依赖。

image.png

非aop循环依赖

image.png

通过调用栈可以看出解决循环依赖的关键是在A对象填充属性前将一个匿名内部类ObjectFactory对象放在SingletonFactory(三级缓存)中,在有依赖对象A的对象B填充属性A时通过getSingleton方法的ObjectFactory.getObject() 直接调用内部类中专门用来获取A半成品对象的getEarlyBeanReference方法,从而完成填充属性。

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

getEarlyBeanReference方法则会循环调用bean后置处理器的getEarlyBeanReference方法,非aop情况下,会调用两个后置处理器,其都是直接返回传参的bean,未做处理。

image.png

aop循环依赖

此处不讲解AOP如何生成代理对象,在下篇文章会进行讲解

在aop代理的情况下,则getEarlyBeanReference方法中会多出一个后置处理器;

image.png

在调用bean后置处理器的getEarlyBeanReference方法中,会通过wrapIfNecessary生成代理对象。

    // Aop提前引用入口
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }

熟悉AOP的应该清楚,aop代理对象是在初始化那一步的后置处理器的postProcessAfterInitialization方法中生成代理对象的,同样是wrapIfNecessary方法,和上面的getEarlyBeanReference方法都出自AbstractAutoProxyCreator类。

    //AOP 创建代理对象入口
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //如果没有被提前代理过
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //最终会调用createProxy,创建代理bean
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

相关文章

网友评论

      本文标题:最易懂Spring循环依赖

      本文链接:https://www.haomeiwen.com/subject/zxoebrtx.html