目录
前言
spring三级缓存用来解决spring的循环依赖问题
目前循环依赖只在属性set注入且单例的情况下才能解决
构造器注入和多例的循环依赖情况下是无法解决的
提示:以下是本篇文章正文内容,下面案例可供参考
一、spring三级缓存是什么?
singletonObjects <ConCurrentHashMap<>> 一级缓存
singletonFactories <HashMap<>> 三级缓存
earlySingletonObjects <HashMap<>> 二级缓存
二、分析步骤
1.循环依赖示例:
@Service
public class AService {
private BService bService;
public AService() {
System.out.println("Aservice 构造方法执行---------");
}
public BService getbService() {
return bService;
}
public void setbService(BService bService) {
this.bService = bService;
}
}
@Service
public class BService {
private AService aService;
public BService() {
System.out.println("bService 构造方法--------");
}
public AService getaService() {
return aService;
}
public void setaService(AService aService) {
this.aService = aService;
}
}
当容器初始化加载两个bean时,会造成A,B相互依赖,查看bean生命周期,可以追踪循环依赖的解决方式
首先容器会通过doGetBean()获取AService,
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
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;
}
// 如果获取不到,则创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//创建
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
通过doCreateBean()方法创建Aservice
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
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));
}
//放入三级缓存后,准备初始化bean实例,接着填充属性操作
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
会先把AService放入三级缓存,
key: beanName value值 : () -> getEarlyBeanReference(beanName, mbd, bean)
具体的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);
}
}
}
AService填充属性,需要注入BService
解析依赖方法:
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
//此处会去获取BService bean实例
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
而容器中还没有Bservice的Bean,及需要先创建BService的bean
BService的创建也是先经过上述步骤
先把BService的未成品的bean放入三级缓存
然后BService的bean 填充属性 AService
这时getSingleton()方法如下
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);
//从一级缓存未找到AService的Bean且allowEarlyReference为true,
//则把AService的Bean放到二级缓存中
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
之后BService的Bean属性填充完毕,创建实例Bean完成,让后将Bean放入的一级缓存
/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
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);
}
}
接下来回到Aservice的Bean的 填充属性方法
获取到Bservice的Bean实例,
属性填充完毕
再把AService的Bean实例放到一级缓存中,
至此实例化ABService完成
总结
循环依赖似乎只要二级缓存就能解决,为何还要三级缓存,
个人理解:其实在最开始放入三级缓存的value,lambda表达式,即用来解决AOP代理的bean相互依赖的的问题,如果需要代理,则提前暴露代理对象放入的其他缓存,否则提前生成普通代理对象实例放入其他缓存即可