managing state in Lift的一种典型方法是创建一个扩展SessionVar的单例对象,就像这个取自the documentation的例子一样:
object MySnippetCompanion {
object mySessionVar extends SessionVar[String]("hello")
}
使用SessionVar
的情况很清楚,我已经根据需要在实践中使用它们。我也大致了解它们是如何在里面工作的。
尽管如此,我还是不禁想知道为什么“会话变量”的机制明显与当前会话相关联(通常只是系统中许多会话中的一个),它被设计为通过单例使用?这与我的直觉相反,乍一看我很想相信Lift能够以某种方式覆盖Scala的语言特征,并使object
与常规Scala有所不同。
即使我现在明白它是如何运作的,但我无法理解这样一种设计的理由,至少在我看来,它打破了最不惊讶的规则。有人可以指出任何优势,或者解释为什么可以做出这样的设计决定吗?
答案 0 :(得分:5)
Lift中的会话变量使用Scala的DynamicVariable
。基本上它们允许您静态引用代码块中的变量,然后调用代码并替换值:
import scala.util.DynamicVariable
val x = new DynamicVariable(1)
def printIt() {
println(x.value)
}
printIt()
//> 1
x.withValue(2)(printIt())
//> 2
因此,每次处理请求时,这些动态变量的范围都会更改为当前会话,完全将当前会话的状态更改隐藏为程序员。
另一种选择是传递一个“sessionID”对象,当您想要访问会话特定数据时,必须使用该对象。不太方便。
答案 1 :(得分:2)
您必须使用object
关键字的原因是object
是唯一的,因为它定义了值和类。这允许Lift调用getClass
来获取唯一标识此SessionVar
与其他任何名称相对应的名称,Lift需要这些名称以便在正确的位置序列化和反序列化每个会话状态。此外,如果SessionVar
在具有两个实例的类中(例如,在两个选项卡中呈现的片段),则它们都将引用相同的会话状态。 (硬币的另一面是,两个不同的会话可以引用相同的SessionVar
实例,并且对每个会话都是正确的。)
实际上有时这是不够的 - 例如,如果你在一个特征中定义一个SessionVar
,并且有两个不同的类来继承这个特征,但你需要它们两个有两个不同的值。在这种情况下,解决方案是覆盖“名称盐”的def,它与getClass
结合使用以识别SessionVar
。