相信不少小伙伴在面试过程中被问到过这个问题,也有不少小伙伴看到这个问题会脱口而出:三级缓存!但是,你真的了解spring解决循环依赖的过程吗?三级缓存是哪三级呢?他们是如何发挥作用的呢?
不少同学一定很好奇三级缓存究竟是哪三级呢,他们是以什么样的形式来发挥作用的呢?
// 单例对象的缓存:bean名称到bean实例。
private final Map singletonObjects = new ConcurrentHashMap<>(256);
// 当前正在创建的bean的名称。
private final Set singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 早期单例对象的缓存:bean名称到bean实例。
private final Map earlySingletonObjects = new ConcurrentHashMap<>(16);
举个例子:有一个BeanA依赖来BeanB,但是BeanB还未完成创建,先对BeanA生成一个临时的代理对象C使BeanA可以用但是不是很完善,并将BeanA存放到earlySingletonObjects容器中,等待BeanB创建完成后再替换回来。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 快速检查没有完整beanObject singletonObject = this.singletonObjects.get(beanName);// 检查成员变量正在创建的bean中有没有if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 如果没有完整的bean,并且当前bean正在创建,尝试从半成品中寻找,如果找到了意味着很大概率发生了循环依赖。//比如A和B循环依赖,所以A在创建之后会放在earlySingletonObjects中,初始化B的时候需要A,此时会尝试在earlySingletonObjects寻找AsingletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 如果半成品里也没有,并且允许早期引用synchronized (this.singletonObjects) {// 加锁防止其他线程修改singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);// 加锁之后再校验一遍确认还是没有if (singletonFactory != null) {// 通过工厂方法创建出来这个bean,并将他放到earlySingletonObjects中singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);// 因为是单例模式,所以可以把工厂删掉了,以后就用它了this.singletonFactories.remove(beanName);}}}}}}return singletonObject;
}
在SpringBoot的启动过程中实际会有两次移除earlySingletonObjects的操作。
AbstractAutowireCapableBeanFactory类的doCreateBean方法,代码有点长,我忽略了其他不重要信息。有兴趣的小伙伴可以自己去源码中阅读。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {/** 忽略部分代码*/if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//添加Singleton Factory会移除一次,虽然此时还没有创建,没错就是这么严谨addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {populateBean(beanName, mbd, instanceWrapper);// 初始化bean,这个方法里的代码在标题《删除earlySingletonObjects放入singletonObjects:完成bean后置处理器》中exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}/**忽略部分代码*/
addSingletonFactory方法代码:
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);}}}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);// 移出earlySingletonObjectsthis.earlySingletonObjects.remove(beanName);// 存入registeredSingletons。此时该bean已经完整了this.registeredSingletons.add(beanName);}}