我在项目中都使用Spring.net作为IOC容器,今天有遇到了以前曾经出现的一个奇怪的bug,描述如下。
我配置了GameRoomConfig对象:
<
object
name
=
"
gameRoomConfig
"
type
=
"
GamePlatform.Entity.Runtime.GameRoomConfig,GamePlatform.Entity
"
>
<
property name
=
"
ID
"
value
=
"
3011
"
/>
<
property name
=
"
GameID
"
value
=
"
DDZ
"
/>
<
property name
=
"
ListenIP
"
value
=
"
192.168.0.206
"
/>
<
property name
=
"
ListenPort
"
value
=
"
9090
"
/>
<
property name
=
"
IP
"
value
=
"
192.168.0.206
"
/>
<
property name
=
"
Port
"
value
=
"
9090
"
/>
<
property name
=
"
MaxUserCount
"
value
=
"
500
"
/>
<property name="GPSCallback" ref="serviceForGPSCallback"/>
</
object
>
在IOC容器中,有多个对象都注入了配置的这个gameRoomConfig对象,而这些配置在以前一年多的时间中一直工作良好,今天我重装系统后,再在VS中启动这个程序就无法正常运行了,原因在于其它依赖于gameRoomConfig的对象在它们自己的Initialize方法中使用gameRoomConfig时候,gameRoomConfig的各个属性还未被赋值。也就是说,gameRoomConfig对象还未被正确设置就被其它依赖对象使用了。我为其它依赖对象加上 depends-on="gameRoomConfig" 来作强制检查也于事无补。
真是奇怪,在一年多以前就遇到过这个问题,后来不知道是什么原因又莫名其妙的自动好了,现在又出现了。当前我的补救方案是,将gameRoomConfig对象由Singleton模式改为SingleCall模式,这样每个依赖对象都使用一个独立的gameRoomConfig对象了。
<
object
name
=
"
gameRoomConfig
"
type
=
"
GamePlatform.Entity.Runtime.GameRoomConfig,GamePlatform.Entity
"
singleton
="false"
>
如果大家也有遇到过类似的问题,请告知一下真正的原因,谢谢。
正解:应该是在错综复杂的依赖关系中引入了循环依赖,我通过移除一个属性依赖,使得系统又恢复正常。上面所述的现象看似问题出在gameRoomConfig对象上,实则不然,我斩断的那个循环依赖链似乎与gameRoomConfig对象的关联不大。
也就是说,如果依赖关系中出现循环依赖,则会导致循环链中的某个对象在其属性未被赋值前就被其它依赖对象所使用。
解决的方案是,斩断循环依赖,这可以通过引入一个中间的Bridge对象做到,在Bridge对象的Initialize方法中,将两者的依赖关系动态的建立起来(这就绕过了Spring的对象依赖的静态检测)。如桥的Initialize方法示例:
public
class
GameInitializer
{
#region
GameRoomConfig
private
GameRoomConfig gameRoomConfig;
public
GameRoomConfig GameRoomConfig
{
set
{ gameRoomConfig
=
value; }
}
#endregion
#region
GPSCallback
private
IGPSCallback gPSCallback;
public
IGPSCallback GPSCallback
{
set
{ gPSCallback
=
value; }
}
#endregion
public
void
Initialize()
{
/*
由于GPSCallback对象引入了循环依赖,斩断它
*/
this
.gameRoomConfig.GPSCallback
=
this
.gPSCallback;
}
}