【问题标题】:Why use singleton controllers in play 2.5?为什么在 play 2.5 中使用单例控制器?
【发布时间】:2016-11-16 21:55:29
【问题描述】:

我刚刚开始,我认为我不太了解它。据我了解,所有控制器都是在创建路由器时作为依赖项创建的。然后它们继续存在,直到应用程序终止时路由器死亡。如果是这种情况,将它们声明为单例似乎是多余的。

【问题讨论】:

  • 您不必将它们声明为单例。你在哪里读到的?
  • 无处可去。但是,如果您查看带有 play 安装的控制器,它们都被注释为单例
  • 啊,我明白了,我在下面放了一个更大的评论 - 它是关于无国籍的。
  • 控制器曾经是 Play Framework 中的对象,然后 DI 出现了 :)

标签: playframework controller


【解决方案1】:

为了摆脱全局状态(这违背了无状态设计的理念)Play 引入了 DI(我认为在 v2.4 左右),在 v2.5 中它现在默认使用注入路由器。 Google Guice 是 Play 打包的默认 DI 框架(您可以使用其他框架,但 Guice 是默认的)。

现在(一般而言)Guice 认为创建新的 Controller 实例比使用单例更快,线程更安全 - 请参阅 Guice docs for more

如果您 have a need 将控制器的实例限制为仅 1,那么您可以将其标记为单例,但您必须将其设为 Thread-safe,因为它将在线程之间共享。

我认为 Activator 模板可以在它们周围添加更多文档来解释为什么它们似乎在不需要它们时生成 @Singleton 控制器,因为它令人困惑。例如,HomeController(在 Play-Scala 种子中)被混淆地声明为 @Singleton,但它没有表现出任何情况。

一般来说,最好不要使用@Singleton,除非您对不可变性和线程安全有相当的了解。如果您认为您有 Singleton 的用例,请确保您正在保护任何共享状态。

简而言之,不要使用@Singleton

【讨论】:

  • 所以最好的做法是将每个控制器声明为@Singleton?
  • 我想我还是有点困惑。我仍然无法看到将创建更多一个实例的时间。所以单例符号似乎仍然是多余的。另外我的印象是所有请求都由同一个线程处理,所以它是否无状态并不重要
  • @user25470 每个请求 1 个线程,否则您的所有请求都必须排队等待轮到 1 个线程,这意味着您的应用程序非常慢。您可能已经在文档中读到 Actions 是非阻塞的——这意味着你永远不应该在控制器操作中做任何可能导致它获得上下文切换(例如 I/O)的事情——这是因为默认Play 的线程池是主机上每个核心 1 个线程。因此,一个线程被分配一个请求,快速执行操作(非阻塞)并快速返回到池中以处理下一个。
【解决方案2】:

如果您有一个由路由器实例化的控制器(即默认值),那么它们就是隐式单例,因为路由器只存在一次。但是,如果您将控制器注入其他地方,您仍然会得到一个新实例,除非它被标记为单例。

来源:https://github.com/playframework/playframework/issues/4508#issuecomment-127820190

【讨论】:

  • 你能举个例子说明你什么时候在别处注入控制器吗?
  • 没有。我认为这是不好的做法。如果你想共享功能,你应该创建一个业务服务或其他一些帮助类。我认为在别处注入控制器的意义在于强调控制器不是真正单例的。
猜你喜欢
  • 2017-07-26
  • 2015-09-30
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多