我面临的问题的(简化)版本如下,在Spring MVC应用程序中:
两名球员可以参加比赛。该游戏包括从相同数据(例如某个国际象棋位置)开始,单独玩游戏(但同时玩!)并在之后比较结果。为了解决这个问题,我有:
对于每个玩家,一个处理游戏动作的对象(例如,在棋盘上移动棋子)。这是一个会话范围的bean,因为它包含特定于播放器的状态信息。称之为'PlayerHandler':
< bean id =“playerHandler”class =“snip.PlayerHandler”scope =“session”> < aop:scoped-proxy /> < /豆腐>
问题是GameHandler需要重新同时使用两个PlayerHandler。但是,由于这是一个代理会话范围的bean,这些引用指向同一个bean,具体取决于我用来访问它的会话。例如。两个球员,“汤姆”和“杰里”:
会话Tom:playerHandler.getGameHandler().getPlayer1().getName()
和playerHandler.getGameHandler().getPlayer2().getName()
都是Tom
会议杰瑞:都是杰瑞。
现在,据我了解,这是预期的行为。我的问题是不“为什么会这样”,这是“我该如何解决这个问题”。我发现自己的解决方案是在GameHandler中设置引用时引用实际的bean而不是代理:
public void setPlayerOne(PlayerHandler playerHandler) {
try {
while (playerHandler instanceof Advised)
playerHandler = (PlayerHandler ) ((Advised) playerHandler ).getTargetSource().getTarget();
} catch (Exception e) {
e.printStackTrace();
}
...
但是,我不确定这是最好的解决方案。所以我正在寻找一些答案:我的设计是错误的 - 如果是这样,你会如何设计?我错过了一个简单的解决方案吗?这是春季限制吗?
答案 0 :(得分:1)
回到你的基本设计,你必须重新考虑你的“PlayerHandler”是否真的是会话范围的,从概念上来说。由于您需要在给定会话范围之外访问它(处理特定会话请求的线程),因此它看起来不是。
重构这种方法的一种方法是将“PlayerHandler”移出到应用程序范围。创建一个全局单例bean,可能称之为“PlayerHandlerHolder”,例如,使用一个映射来保存键入会话ID的PlayerHandler实例。为了防止无限填充此映射,您可以实现一个会话侦听器,在会话销毁时从映射中删除PlayerHandler实例。
答案 1 :(得分:0)
解决问题的一种方法是create a custom scope,称之为“游戏”。现在像这样定义你的bean:
<bean id="playerHandler" class="snip.PlayerHandler" scope="game">
<aop:scoped-proxy /></bean>