欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > spring源码 循环依赖

spring源码 循环依赖

2024/11/30 7:33:15 来源:https://blog.csdn.net/Dennis_nafla/article/details/140807100  浏览:    关键词:spring源码 循环依赖

spring框架两大核心:IOC和AOP

IOC(Inverse of Control)控制反转

将对象的创建权交给 Spring 容器去创建,利用了工厂模式将对象交给容器管理,只需要在spring配置文件中配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。不需要我们手动new去创建对象,大大降低了代码间的耦合度,使资源更加容易管理。

AOP(Aspect Oriented Programming)面向切面编程

通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。

循环依赖

问题描述

A有属性b,B有属性a,创建A时对b属性赋值需要有b对象,如果没有b就创建,但是创建B又需要对属性a赋值,这样就构成了循环依赖

前置知识

Spring在创建Bean的过程中分为三步

实例化 ,对应方法:AbstractAutowireCapableBeanFactory中的createBeanInstance方法

属性注入,对应方法:AbstractAutowireCapableBeanFactorypopulateBean方法

初始化,对应方法: AbstractAutowireCapableBeanFactoryinitializeBean方法

其中AOP是在初始化阶段完成的

解决方案:三级缓存(3个Map)

核心思想是:bean进行实例化操作后,不需要进行依赖注入(属性赋值)操作就放入缓存中,当其他bean需要时直接从缓存中拿就行了

  • 一级缓存为:singletonObjects 缓存已经创建好的bean对象(完成了实例化,属性注入,初始化)。
  • 二级缓存为:earlySingletonObjects 缓存只完成了实例化,但是还未进行属性注入及初始化的对象
  • 三级缓存为:singletonFactories 提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象

利用三级缓存解决循环依赖的流程(假设A对象中有属性b,B对象中有属性a)

首先创建A对象,先后查询一级,二级,三级缓存,都没有A这个bean对象,所以先进行实例化,实例化完成后存到三级缓存中,然后进行属性注入,A类只有一个类型为B的属性b,先后查询一级,二级,三级缓存,都没有B这个bean对象,先实例化,实例化后存到三级缓存中,进行属性注入,B类只有一个类型为A的属性a,查一级缓存,没有,查二级缓存,没有,查三级缓存,找到提前暴露的工厂,通过工厂创建A对象,将三级缓存中的创建A对象的工厂删除(remove),将创建好的A对象存进二级缓存,然后赋值给B类的a属性,B类进行初始化,此时已经创建完成,就赋值给A类的b属性,A类进行初始化,创建完成。

现在有这样一个经典的循环依赖(先不考虑AOP)

执行流程:

首先是创建A:

在getSingleton(beanName,true)方法中,依次查询一二三级缓存,发现都没有beanName为A的映射,就跳转到重载方法getSingleton(beanNeme, singletonFactory)中,这个方法的用途是创建bean,因为缓存中都没有,所以要新创建这个A对象。但是并不是简单调用createBean这个方法就完了,还要将创建好的bean(完成实例化,属性注入,初始化)存进一级缓存singletonObjects

来看下getSingleton(beanName,singletonFactory)方法源码:(看蓝色重点部分)

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) {// ....// 省略异常处理及日志// ....// 在单例对象创建前先做一个标记// 将beanName放入到singletonsCurrentlyInCreation这个集合中// 标志着这个单例Bean正在创建// 如果同一个单例Bean多次被创建,这里会抛出异常beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {// 上游传入的lambda在这里会被执行,调用createBean方法创建一个Bean后返回singletonObject = singletonFactory.getObject();newSingleton = true;}// ...// 省略catch异常处理// ...finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}// 创建完成后将对应的beanName从singletonsCurrentlyInCreation移除afterSingletonCreation(beanName);}if (newSingleton) {// 添加到一级缓存singletonObjects中addSingleton(beanName, singletonObject);}}return singletonObject;}
}

这里的getObject()方法会调用createBean方法

真正完成这些的是doCreateBean方法

在doCreateBean方法中:

先进行实例化,实例化后对实例化后的bean对象封装成一个对象工厂,存进三级缓存singletonFactorys,然后才进行属性注入和初始化

// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.//向容器中缓存单例模式的Bean对象,以防循环引用//判断是否是早期引用的bean,如果是,则允许其提前暴露引用// 这里判断的逻辑主要有三个∶//1.是否为单例//2 是否允许循环引用//3.是否是在创建中的beanboolean 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");}//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用//将还没完全配置好的bean存入到三级缓存中供其他bean使用(暴露引用)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));//这里的getEarlyBeanReference()方法,并不是在此调用,而是声明好了方法//具体的调用在Spring的AbstractBeanFactory的doGetBean的第三行调用// DefaultSingletonBeanRegistry类的getSingleton方法中,调用// singletonFactory.getObject()(单例工厂的getObject方法返回实例对象)}// Initialize the bean instance.//Bean对象的初始化,依赖注入在此触发//这个exposedObject在初始化完成之后返回作为依赖注入完成后的BeanObject exposedObject = bean;//暴露的对象try {//属性注入populateBean(beanName, mbd, instanceWrapper);//初始化bean,过程如下://1.判断是否实现了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware方法,//如果有,则设置相关的属性//2.调用bean初始化前的前置(BeanPostProcessor)操作//3.执行初始化的方法//如果有InitializingBean,则调用afterPropertiesSet//如果有InitMethod,则调用初始方法//4.调用bean初始化的后置(BeanPostProcessor)操作//初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}

这里将实例化后的bean添加到三级缓存singletonFactorys调用了方法:

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

这里的第二个参数是一个lambda表达式 () -> getEarlyBeanReference(beanName, mbd, bean),

这个addSingletonFactory是什么呢?

在通过三级缓存得到beanName对应的工厂后(objectFactory),调用getObject方法来得到对象,这个对象实际上就是通过getEarlyBeanReference方法创建的。

addSingletonFactory方法源码:

// 这里传入的参数也是一个lambda表达式,() -> getEarlyBeanReference(beanName, mbd, bean)
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 添加到三级缓存中this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
}

addSingletonFactory方法源码:

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

回到流程中

此时A这个bean已经实例化好并且存进三级缓存singletonFactorys中,下一步是属性注入,A中只有B类型的b这一个属性,和创建A时一样,还是

getBean->doGetBean->getSingleton(bean,true)->getSingleton(b,ObjectFactory)

->createBean->doCreateBean

实例化后存到三级缓存中,进行属性注入,B里面只有A类型的a这一个属性,依次查询一二三级缓存,然后在第三级缓存中查询到A,得到A的工厂,调用getObject()方法得到只进行了实例化的a,将a赋值给B,再进行初始化,此时B已经创建完成,将B赋值给A的b属性,A进行初始化,此时A也创建完成。

这里还要注意:从三级缓存中获取完之后,会将工厂得到的对象存进二级缓存earlySingletonObjects,然后再三级缓存中删除该beanName对应的映射。

考虑AOP的情况

如果启用了AOP,那么在A的创建过程中:

在实例化后进行存入三级缓存时,存的是代理后的对象

在B的创建过程中:

在属性注入时,从三级缓存中获取A得到的也是代理后的对象

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;
}
public Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);// 如果需要代理,返回一个代理对象,不需要代理,直接返回当前传入的这个bean对象return wrapIfNecessary(bean, beanName, cacheKey);
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com