在使用spring的场景中,有时会碰到如下的一种情况,即bean之间的循环引用。即两个bean之间互相进行引用的情况。这时,在spring xml配置文件中,就会出现如下的配置:
1
2
|
<
bean
id
=
"beanA"
class
=
"BeanA"
p:beanB-ref
=
"beaB"
/>
<
bean
id
=
"beanB"
class
=
"BeanB"
p:beanA-ref
=
"beaA"
/>
|
并且,在一般情况下,这个配置在现有的spring3.0中是可以正常工作的,前提是没有对beanA和beanB进行增强。但是,如果任意一方进行了增强,比如通过spring的代理对beanA进行了增强,即实际返回的对象和原始对象不一致的情况,在这种情况下,就会报如下一个错误:
1
2
3
4
5
6
|
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."
|
这个错误即对于一个bean,其所引用的对象并不是由spring容器最终生成的对象,而只是一个原始对象,而spring不允许这种情况出现,即持有过程中间对象。那么,这个错误是如何产生的,以及在spring内部,是如何来检测这种情况的呢。这就得从spring如何创建一个对象,以及如何处理bean间引用,以及spring使用何种策略处理循环引用问题说起。
这里会涉及到在spring内部所使用的两个内部属性,singletonFactories和earlySingletonObjects,这两个属性在类DefaultSingletonBeanRegistry中被定义,定义如下:
1
2
3
4
5
|
/** Cache of singleton factories: bean name --> ObjectFactory */
private
final
Map<String, ObjectFactory> singletonFactories =
new
HashMap<String, ObjectFactory>();
/** Cache of early singleton objects: bean name --> bean instance */
private
final
Map<String, Object> earlySingletonObjects =
new
HashMap<String, Object>();
|
官方对此的属性定义不是很明确,这里我们可以这样来理解。
- singletonFactories,用于存储在spring内部所使用的beanName->对象工厂的引用,一旦最终对象被创建(通过objectFactory.getObject()),此引用信息将删除
- earlySingletonObjects,用于存储在创建Bean早期对创建的原始bean的一个引用,注意这里是原始bean,即使用工厂方法或构造方法创建出来的对象,一旦对象最终创建好,此引用信息将删除
从上面的解释,可以看出,这两个对象都是一个临时工。在所有的对象创建完毕之后,此两个对象的size都为0。
那么再来看下这两个对象如何进行协作:
方法1:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
/**
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
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);
}
}
}
|
方法2:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* 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</code> if none found
*/
protected
Object getSingleton(String beanName,
boolean
allowEarlyReference) {
Object singletonObject =
this
.singletonObjects.get(beanName);
if
(singletonObject ==
null
) {
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 != NULL_OBJECT ? singletonObject :
null
);
}
|
方法3:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/**
* 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 !=
null
? singletonObject : NULL_OBJECT));
this
.singletonFactories.remove(beanName);
this
.earlySingletonObjects.remove(beanName);
this
.registeredSingletons.add(beanName);
}
}
|
方法1和方法2中的官方注释都很明显地显示了,针对于循环引用的处理,即能够处理循环引用问题。
详细见后两篇
Spring中循环引用的处理-2
Spring中循环引用的处理-3
转载请标明出处:i flym
本文地址:http://www.iflym.com/index.php/code/201208280001.html
如果你觉得此篇文章对你有用,不妨小小地捐助一下:)以支持原创
相关文章:
- Spring中循环引用的处理-3
- Spring中循环引用的处理-2
- Spring中获取一个bean的流程-2
- Spring中获取一个bean的流程-1
- Spring中Autowired注解,Resource注解和xml default-autowire工作方式异同