最易懂Spring循环依赖

网友投稿 864 2022-10-24

最易懂Spring循环依赖

最易懂Spring循环依赖

前言

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

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

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

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

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

介绍

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

SpringIOC中分为两种情况:

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

Spring解决循环依赖的前提:

只支持单例对象。原型prototype的场景如果循环依赖就会造成无限套娃,所以是不被支持的,spring会抛出异常。 我们谈的循环依赖都是依据单例对象相互依赖产生的循环依赖问题。不支持构造构造器注入的循环依赖(这里说的是A、B对象均采用构造方法注入)。

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

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

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

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

非aop循环依赖

通过调用栈可以看出解决循环依赖的关键是在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,未做处理。

aop循环依赖

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

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

在调用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; }

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:ThinkORM:一个优雅的Go语言ORM框架
下一篇:TypeSDK- 手游渠道 SDK 统一接入框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~