0
点赞
收藏
分享

微信扫一扫

spring 如何解决循环依赖(五)

伢赞 2022-03-25 阅读 83

spring如何解决循环依赖
主要通过三级缓存解决循环依赖,三级缓存分别作用是什么?
1.singletonObjects单例池主要缓存spring单例bean,是经过完整bean生命周期的bean实例。
2.earlySingletonObjects缓存早期单例对象,指未经过属性注入和初始化的bean。
3.singletonFactories缓存的ObjectFactory对象,调用getObject获取单例对象。

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					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) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

singletonObjects一级缓存何时存入的?当创建bean成功时,会进行缓存升级,将二级三级缓存抹掉,加入到singletonObjects一级缓存。具体加入逻辑在getSingleton方法中,通过调用addSingleton方法。

sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
	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);
		}
	}

三级缓存singletonFactories是在何时存入的?在createBeanInstance之后就会将早期对象加入singletonFactories。

		boolean 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");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

当调用getObject方法时会执行getEarlyBeanReference,主要逻辑是遍历SmartInstantiationAwareBeanPostProcessor调用getEarlyBeanReference方法。

	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
				exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
		return exposedObject;
	}

循环依赖场景
下面根据一个循环依赖场景,假设A对象内部依赖B,B对象内部依赖A,形成循环依赖,看一下spring解决循环依赖处理流程。

在这里插入图片描述
为什么需要三级缓存
spring为什么需要三级缓存,两级缓存能解决循环以来吗?
如果用二级缓存存储代理对象,然后属性注入时去二级缓存找对应的bean,好像也没啥问题。
这样就违背了spring设计原则,因为spring aop是在初始化之后进行的,这样都要改成在实例化之后进行aop,并把代理类加入到二级缓存。

举报

相关推荐

0 条评论