java spring 13 循环依赖 现在doGetBean方法中使用,而后在doCreateBean方法

1.举个例子:
 所谓循环依赖,就是A中依赖了B,而B又依赖了A,如下:

@Service
public class BeanServiceA {
    private String name = "serviceA";

    @Autowired
    BeanServiceB beanServiceB;

    public void testMethod() {
        System.out.println();
    }
}

@Service
public class BeanServiceB {
    private String name = "serviceA";

    @Autowired
    BeanServiceA beanServiceA;
}



本文举栗中A要进行代理,而B不需要

2.Bean创建过程及循环依赖解决:
 先介绍一下循环依赖涉及的重点方法DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)


//返回在给定名称下注册的(原始)singleton对象。
 //检查已经实例化的singleton,并允许早期对当前创建的单例的引用(解析循环引用)
 
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 快速检查没有完整单例锁的现有实例,如果有就直接返回,如果没有,进入创建流程
   // 先从一级缓存中获取
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      // earlySingletonObjects:早期singleton对象的缓存:bean名称到bean实例。
      // 从二级缓存中获取早期的bean实例
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // 在完整的单例锁中一致地创建早期引用
            // this.singletonObjects:singleton对象的缓存:bean名称到bean实例
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               // 这里为什么要再次从earlySingletonObjects中获取一次?
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  // 从各级缓存中都没有获取到singletonObject,进入创建流程
                  // 从三级缓存中获取工厂对象
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     // 存入二级缓存
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     // 从三级缓存中删除
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

public boolean isSingletonCurrentlyInCreation(String beanName) {
	return this.singletonsCurrentlyInCreation.contains(beanName);
}

2.1 BeanServiceA的创建:

在创建bean时,会调用doGetBean方法,首先通过getSingleton方法从缓存中看是否能获取到该bean:

a. 先从一级缓存singletonObjects中获取,发现获取不到,然后看是否在创建中,显然初次创建时不成立,即getSingleton返回null
b. 调用第14行的getSingleton方法触发createBean回调,进行bean的生命周期

在这里插入图片描述

在第14行的getSingleton,会将当前beanName放入singletonsCurrentlyInCreation,表示当前bean正在创建:

这里重写的是singletonFactory的getobject()方法,变成createBean方法

这里的getSingleton与上面的getSingleton不同,这个是重点

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) {
         // 如果当前beanFactory正在被销毁则直接抛出异常,不允许创建单例bean
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            // 这里日志说的是,创建singleton bean的共享实例
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         // 前置处理
         // 将bean加入singletonsCurrentlyInCreation,用于循环依赖的校验
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         // 核心的创建逻辑还是在这里,和老版本方法的差距在于,
         // 老版本方法从三级缓存中获取单例工厂。新版本使用形参中用户提供的单例工厂
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // 这里主要是异常处理逻辑,不过多赘述
            // singleton对象是否同时隐式出现,如果出现了,继续执行,因为异常指示该状态
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            // 后置处理
            // 主要将bean从singletonsCurrentlyInCreation中移除
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            // 加入到缓存中,并调整各级缓存中的状态记录
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

在这里插入图片描述

beforeSingletonCreation(beanName):


protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

afterSingletonCreation(beanName):

protected void afterSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
                throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
}

addSingleton():


protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

2.1.1 重写的getobject方法=CreateBean方法------->doCreateBean方法,实例化BeanServiceA不完整对象:

a.一般通过createBeanInstancec实例化不完整的BeanServiceA对象

b.将不完整对象以及BeanDefinition代表的lambda表达式写入(三级缓存)

c.属性填充BeanServiceB

d.初始化BeanServiceA时调用AOP后置处理器进行AOP处理

e.处理提前暴露的场景,保证返回同一个代理对象
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	... ... ...
	if (instanceWrapper == null) {
		// a. 一般通过createBeanInstancec实例化不完整的BeanServiceA对象
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	... ... ...
	// 默认单例&&默认循环引用&&该bean正在创建,条件成立
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		... ... ...
		// b. 将不完整对象以及BeanDefinition代表的lambda表达式写入三级缓存
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		// c. 属性填充BeanServiceB
		populateBean(beanName, mbd, instanceWrapper);
		// d.初始化时调用AOP后置处理器进行AOP处理
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	... ... ...
	// e.处理提前暴露的场景,保证返回同一个代理对象
	if (earlySingletonExposure) {
		// 见上文第1节的介绍,由于第二个参数是false,所以只会查到第二级缓存
		// 所以这里就是查看第二级缓存能不能取到值,取到就意味着涉及提前AOP
		Object earlySingletonReference = getSingleton(beanName, false);
		// 涉及提前AOP,从二级缓存中获取提前AOP的代理对象
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				// 保证循环依赖且涉及AOP时,返回同一个代理对象,下文有结束
				exposedObject = earlySingletonReference;
			}
			... ... ...
		}
	}
	return exposedObject;
}

addSingletonFactory将不完整对象以及BeanDefinition代表的lambda表达式写入三级缓存同时将不完整的对象

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
			// 将不完整对象以及BeanDefinition代表的lambda表达式写入三级缓存
			this.singletonFactories.put(beanName, singletonFactory);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

2.1.2. 属性填充BeanServiceB:

当填充BeanServiceB会重复上文第1节中的内容:

a. 先从一级缓存singletonObjects中获取,发现获取不到,然后看是否在创建中,显然初次创建时不成立,即getSingleton返回null

b. 调用第14行的getSingleton方法触发createBean回调,进行bean的生命周期

c. 实例化BeanServiceB的不完整对象,并将lambda写入三级缓存

d. 属性填充BeanServiceA(见下文2.1.2.1)

e. initializeBean初始化BeanServiceB

2.1.2.1 循环依赖处理属性填充BeanServiceA:

a). 先从一级缓存singletonObjects中获取,发现获取不到,然后看是否在创建中
  显然正在创建,singletonsCurrentlyInCreation有beanServiceA

b). 从二级缓存中获取 → 获取不到 → 从三级缓存获取 → lambda表达式回调(见下文2.1.2.1.1)

c). 将不完整对象BeanServiceA写入二级缓存,三级缓存删除该对象lambda表达式(上文1中getSingleton方法)

d). 返回不完整的BeanServiceA对象

总结:

现在设有两个bean,分别叫做A和B,A中有成员变量B,B中有成员变量A,他们构成了一个标准的循环依赖。

spring首先加载到A,实例化A,前期一切如常,执行完工厂的getObject()方法之后,也就是实例化了A,但尚未对A进行属性注入的时候,会开始调整各级缓存中的内容。此时的各级缓存的情况如下:

A:一级缓存中没有,二级缓存中没有,三级缓存中有

这一次getSingleton()方法执行完成后,缓存的状态就是上面这样的。

在后面的populateBean()方法执行的时候,会在A的内部注入B,此时,需要去获取B的实例,还是正常的通过getBean()方法去初始化B,到这一步,缓存的情况是这样子的:

A:一级缓存中没有,二级缓存中没有,三级缓存中有

B:一级缓存中没有,二级缓存中没有,三级缓存中有

随后会执行populateBean()方法去填充B中的属性,但这个时候会有问题了,B中有一个属性是A,而A,尚未实例化完毕。此时此刻,再去调用getSingleton()方法获取A的实例,就会有不一样的结果。

一级缓存中没有A,说明A没有创建完成,但此时的正在创建的bean的列表中,是有A的,说明A正在创建,尚未完成。

再去二级缓存中获取A,由于B是第一个在创建过程中和A之间存在循环依赖的,所以此时二级缓存中也没有A。

再去三级缓存中找A,由于A已经完成了实例化流程,且没有进行了初始化,因此,三级缓存中是有A的。取出三级缓存中的A,其实是AFactory,执行getObject()拿到A的实例的引用(其实本质上A的引用是个占位符,A在内存中的地址,就已经确定了,不会变了)。将其装入二级缓存,并从三级缓存中清除A。

此时的缓存情况

A:一级缓存中没有,二级缓存中有,三级缓存中没有

B:一级缓存中没有,二级缓存没有,三级缓存中有

然后B继续执行下去,createBean()方法执行完毕,后续方法也正常执行,B成功创建,但B中的A的属性尚未注入。此时的缓存情况如下

A:一级缓存中没有,二级缓存中有,三级缓存中没有

B:一级缓存中有,二级缓存中没有,三级缓存中没有,正在创建的bean列表中没有

此时循环依赖的问题就已经解决了,B已被成功创建。回到A的创建逻辑,拿到B的实例,A将其注入到自己的属性中,A也完成创建。此时的缓存情况如下:

A:一级缓存中有,二级缓存中有,三级缓存中没有,正在创建的bean列表中没有

B:一级缓存中有,二级缓存中没有,三级缓存中没有,正在创建的bean列表中没有

4.什么是三级缓存?

	// 一级缓存,用于存放完整的单例bean
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	// 二级缓存,用于存放原始(不完整)的对象,用于解决循环依赖
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	// 三级缓存,存放函数式接口,用于解决循环依赖
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);


详细:

缓存机制

singletonObjects:一级缓存,里面保存的是一个已经完全实例化完整的bean

earlySingletonObjects:二级缓存,里面保存的是一个已经初始化,尚未实例化的对象

singletonFactories:三级缓存,里面保存了一个对象生成的ObjectFactory方法,里面会调用createBean方法

还有另外两个属性:

singletonsCurrentlyInCreation:正在创建的单例名称队列

registeredSingletons:已经创建成功的单例名称列表

earlySingletonObjects二级缓存和循环依赖问题是息息相关的,对象在创建之后,进行注入过程中,发现产生了循环依赖,那么会将对象放入到这个队列,并且从singletonFactories中移除掉。

4.1 为什么二三级缓存用HashMap,而不像一级缓存使用ConcurrentHashMap?

现有逻辑是,二三级缓存的操作是在synchronized代码块里面操作的(见下方10、11行代码) ·
这已经是线程安全的了,所以没有必要使用ConcurrentHashMap

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

4.2 为什么二三级缓存初始容量是16,一级缓存是256?

上面3.2分析可知,为保证单例,二三级缓存是一次性的,所以没必要那么大容量
而一级缓存是保存完整的单例bean,ioc管理的bean数量也不小,所以容量就大了点

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值