spring循环依赖相关问题

spring解决循环依赖使用了三级缓存,三级缓存分别为:

类:DefaultSingletonBeanRegistry
/** Cache of singleton objects: bean name to bean instance. */
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name to bean instance. */
//二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. */
//三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);


@FunctionalInterface
public interface ObjectFactory<T> {

	/**
	 * Return an instance (possibly shared or independent)
	 * of the object managed by this factory.
	 * @return the resulting instance
	 * @throws BeansException in case of creation errors
	 */
	T getObject() throws BeansException;

}

一级缓存存储成品对象

二级缓存存储半成品对象

三级缓存存储函数式接口ObjectFactory(lambda表达式) 当调用接口的getObject方法时才会执行接口中的逻辑。

向三级缓存中存储的具体方法如下:
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
addSingletonFactory方法中传入了beanName以及函数式接口,接口中调用了getEarlyBeanReference方法。
addSingletonFactory方法如下:
    (如果一级缓存中该beanName已经存在,表示该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);
      }
   }
}



getEarlyBeanReference方法如下:
    (从getEarlyBeanReference方法层层递进可以看到底层实现是JDK和cglib的动态代理)
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;
}

即调用getObject()方法时会执行getEarlyBeanReference方法!!!

循环依赖的问题:

1.三个依赖的读取顺序是什么?

        先读一级缓存,再读二级缓存,最后读取三级缓存

2.为什么存二级缓存时要把三级缓存删掉,存一级缓存时要把二级缓存删掉?

        因为能从一级缓存中读到数据时,就没有必要再去读二级和三级了,二级同理。

3.三个缓存中存储的都是什么对象?

        一级缓存:成品对象

        二级缓存:半成品对象

        三级缓存:lambda表达式

4.用一个缓存能解决循环依赖的问题吗?

        不能,因为对于同一个对象来说,这一个map中既要存储该对象的成品对象,又要存储该对象的半成品对象,从map中读取对象时,无法判断获取的是成品对象,还是半成品对象,所以一个缓存无法解决循环依赖的问题。

5.用两个缓存能解决循环依赖的问题吗?

        可以解决循环依赖的问题,但是有个前提条件:运行过程中不会创建代理对象,则两个缓存可以解决循环依赖的问题,如果运行过程中会创建代理对象,则必须使用三级缓存。

6.为什么使用三级缓存能解决问题?***

  • 创建代理对象是在哪个步骤?在beanPostProcessor的after方法中会完成动态代理对象的创建
  • 创建代理对象时是否需要原始对象?需要
  • 根据上面两个前提条件,我们发现一个问题:刚开始的时候创建了原始对象,然后再根据原始对象创建了代理对象,在对外暴露对象时应该向外暴露原始对象还是代理对象?
  • 针对上面的问题,spring给出的方案是在生成代理对象时,使用代理对象覆盖原始对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值