46

当我阅读 scalatra 的源代码时,我发现有一些代码如下:

protected val _response   = new DynamicVariable[HttpServletResponse](null)
protected val _request    = new DynamicVariable[HttpServletRequest](null)

有一个有趣的类名为DynamicVariable. 我看过这个类的文档,但我不知道什么时候以及为什么我们应该使用它?它有一个withValue()通常被使用的。

如果我们不使用它,那么我们应该使用什么代码来解决它解决的问题?

(我是scala的新手,如果你能提供一些代码,那就太好了)

4

3 回答 3

56

DynamicVariable is an implementation of the loan and dynamic scope patterns. Use-case of DynamicVariable is pretty much similar to ThreadLocal in Java (as a matter of fact, DynamicVariable uses InheritableThreadLocal behind the scenes) - it's used, when you need to do a computation within an enclosed scope, where every thread has it's own copy of the variable's value:

dynamicVariable.withValue(value){ valueInContext =>
  // value used in the context
} 

Given that DynamicVariable uses an inheritable ThreadLocal, value of the variable is passed to the threads spawned in the context:

dynamicVariable.withValue(value){ valueInContext =>
  spawn{
    // value is passed to the spawned thread
  }
}

DynamicVariable (and ThreadLocal) is used in Scalatra for the same reason it's used in many other frameworks (Lift, Spring, Struts, etc.) - it's a non-intrusive way to store and pass around context(thread)-specific information.

Making HttpServletResponse and HttpServletRequest dynamic variables (and, thus, binding to a specific thread that processes request) is just the easiest way to obtain them anywhere in the code (not passing through method arguments or anyhow else explicitly).

于 2011-02-25T12:22:14.150 回答
24

Vasil 很好地回答了这个问题,但我将添加一个额外的简单示例,可能会进一步帮助理解。

假设我们必须使用一些使用 println() 的代码来写整个标准输出。我们希望此输出转到日志文件,但我们无权访问源。

  • println()用途Console.println()
  • Console.println()(幸运的是)基于默认DynamicVariable[PrintStream]java.lang.System.out
  • Console定义withOut只转发到动态变量的withValue

我们可以使用它来简单地解决我们的问题:

def noisy() { println("robot human robot human") }
noisy() // prints to stdout
val ps = new java.io.PrintStream("/tmp/mylog")
scala.Console.withOut(ps) { noisy() } // output now goes to /tmp/mylog file
于 2013-03-18T14:48:09.217 回答
18

这是一个最小的片段:

val dyn = new DynamicVariable[String]("withoutValue")
def print=println(dyn.value)
print
dyn.withValue("withValue") {
  print
}
print

输出将是:

withoutValue
withValue
withoutValue
于 2015-05-11T10:12:22.297 回答