在之前的博客中我们已经多次提到了循环引用,但是都没有细讲,就是希望可以单独拿出来看一下。下面就开始吧!
首先创建了循环引用的三个类,他们的引用关系如下图:
在客户端调用效果如下图:
开始啃源码吧!之前讲过的代码我们就不贴,只放我们之前没讲的代码,其他代码一带而过,直接到bean实例化后填充属性:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
...
//里面有一个classRoom属性值,classRoom还没有实例化
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
...
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
在这我们还要注意一点,当一个bean实例化完,还没有填充属性的时候,它会被放到singletonFactories这个三级缓存中,在我看来,主要是为了解决循环引用问题,通过分析后面的代码我们会更加清晰这样做的目的。
这个方法里面我们关注的只有上面这些代码,一个是获取要实例化的bean的要填充的属性值,另外就是开始填充属性,在这里,只有一个属性要填充,就是classRoom,但是他还没有被实例化,我们看接下来是怎么处理的。
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//判断有没有需要填充的属性
if (pvs.isEmpty()) {
return;
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
...
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//需要填充的属性有没有被转换成指定的类型
if (mpvs.isConverted()) {
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
...
}
}
//属性值没有被转换,需要进行类型转换
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//得到一个类型转换器,在本文要讲的循环引用的解决他是核心
BeanDefinitionValu