spring循环依赖

循环依赖死循环
题目:有连个类,A和B类,其中A类依赖了B类,B类也依赖了A类
①:加载bean定义;
②循环创建bean
进行第一次循环执行getBean方法
(1)实例化
拿到A的class文件,通过反射实例化
(2)属性赋值
拿到A类当中所有的属性,进行循环,判断属性当中有没有@Autowired注解;
此时我们知道了A类存在B被@Autowired注解修饰,重复调用getBean方法,通过B的getName
递归创建B,创建完成后把值set给A的里的B;
(3)初始化
忽略
(4)添加到一级缓存中
把A类放到一级缓存中;

使用二级缓存解决循环依赖:、
A类:
1、bean定义;
2、new
new类,加入二级缓存中
3、填充属性
需要把B类填充到A类中
从二级缓存中拿A类到注入B中,B创建完成,可以进行下一步
4、初始化
5、加入单例池
使用三级缓存解决循环依赖
如果我们给A类添加了AOP代理类,二级缓存将无法解决该问题;
1、bean定义;
2、new //保存lambda表达式到三级缓存中(lambda表达式时bean的半成品,是生成bean对象的工厂方法),如果没有用到循环依赖,这一步将没有作用,但是必须要走这一步为了防止有循环依赖产生,而我们没有对应的方法;
3、填充属性 -->如果被AOP代理了,那么取三级缓存中找lambda表达式,执行其工厂方法,生成aop代理类,保存到二级缓存中,并且删除三级缓存中的bean的半成品
需要把B类填充到A类中
从二级缓存中拿A类到注入B中,B创建完成,可以进行下一步
AOP正常情况下是在这边执行的,在循环依赖的情况下将不在这边执行,而是判断二级缓存中是否已经存有对象了,直接从二级缓存中
拿到对象即可,如果不是AOP的话,那么将是第二步执行的new也就是初始对象;
如果没有三级缓存,那么每次去二级缓存中拿对象执行singleFactory.getObject(),都会产生一个新的代理对象,这明显不合理,在spring中所有的对象都是单例对象,不然一个name对应两个不同的对象,这是明显不行的;所以如果只有二级缓存将不能解决这个问题;
4、初始化
如果上面做了AOP这边是不会做aop的,有一个专门的类负责判断,与创建AOP,是由那个专门管理AOP的类来管理的和其他的无关;
5、加入单例池(一级缓存)
重点代码

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		/**
		 * 第一步:我们尝试去一级缓存(单例缓存池中去获取对象,一般情况从该map中获取的对象是直接可以使用的)
		 * IOC容器初始化加载单实例bean的时候第一次进来的时候 该map中一般返回空
		 */
		Object singletonObject = this.singletonObjects.get(beanName);
		/**
		 * 若在第一级缓存中没有获取到对象,并且singletonsCurrentlyInCreation这个list包含该beanName
		 * IOC容器初始化加载单实例bean的时候第一次进来的时候 该list中一般返回空,但是循环依赖的时候可以满足该条件
		 */
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				/**
				 * 尝试去二级缓存中获取对象(二级缓存中的对象是一个早期对象)
				 * 何为早期对象:就是bean刚刚调用了构造方法,还来不及给bean的属性进行赋值的对象
				 * 就是早期对象
				 */
				singletonObject = this.earlySingletonObjects.get(beanName);
				/**
				 * 二级缓存中也没有获取到对象,allowEarlyReference为true(参数是有上一个方法传递进来的true)
				 */
				if (singletonObject == null && allowEarlyReference) {
					/**
					 * 直接从三级缓存中获取 ObjectFactory对象 这个对接就是用来解决循环依赖的关键所在
					 * 在ioc后期的过程中,当bean调用了构造方法的时候,把早期对象包裹成一个ObjectFactory
					 * 暴露到三级缓存中
					 */
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//从三级缓存中获取到对象不为空
					if (singletonFactory != null) {
						/**
						 * 在这里通过暴露的ObjectFactory 包装对象中,通过调用他的getObject()来获取我们的早期对象
						 * 在这个环节中会调用到 getEarlyBeanReference()来进行后置处理
						 */
						singletonObject = singletonFactory.getObject();
						//把早期对象放置在二级缓存,
						this.earlySingletonObjects.put(beanName, singletonObject);
						//ObjectFactory 包装对象从三级缓存中删除掉
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
//允许早期对象的引用
		if (earlySingletonExposure) {
			/**
			 * 去缓存中获取到我们的对象 由于传递的allowEarlyReferce 是false 要求只能在一级二级缓存中去获取
			 * 正常普通的bean(不存在循环依赖的bean) 创建的过程中,压根不会把三级缓存提升到二级缓存中
			 */

			Object earlySingletonReference = getSingleton(beanName, false);
			//能够获取到
			if (earlySingletonReference != null) {
				//经过后置处理的bean和早期的bean引用还相等的话(表示当前的bean没有被代理过)
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				//处理依赖的bean
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值