是否每个 Play 框架 Web 请求都使用新的依赖注入控制器实例处理,但是静态控制器方法呢?
Is each Play framework web request handled with a new dependency injected controller instance, but then what about static controller methods?
我的问题是关于 Java 的 Play 框架中控制器的生命周期,如果控制器是有状态实例或使用静态方法的无状态,以及如何在控制器代码中使用依赖注入。
是否每个 Web 请求都由 Play 控制器的新实例处理 class,即控制器是否可以将状态存储在注入控制器构造函数的服务等字段中?
(在文档中的哪个位置进行了解释?)
关于控制器是有状态实例还是使用静态方法的无状态控制器,Play 框架自早期版本以来是否发生了变化(如果是,是什么版本?)?
您在哪里可以看到有关在使用有状态控制器时框架如何将服务注入控制器实例的代码示例以及如何将服务注入静态控制器方法的示例?
关于后者,即注入静态方法,我想这要么必须是框架将添加的方法的参数,要么如果不可能的话,您可能不得不从内部使用服务定位器方法例如实例化一个 Guice 模块 class,然后在静态控制器方法中使用 "injector.getInstance"。
下一页的 "Dependency injecting controllers" 部分涉及此主题:
https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection
但是,它没有显示代码如何实际将服务注入控制器实例(但可能与其他 "components" 相同的方式,即使用 @Inject 注释),当然它目前没有显示如何将 DI 与静态控制器方法结合使用。
我对这些事情感到困惑,因为我没有找到明确说明我的问题的文档,而且我还在一本 Play 书中(从 2013 年开始)读到控制器方法应该被编程为无状态并且控制器方法应该保持静止。
但是,当现在使用激活器为具有最新 Play 版本 (2.4.6) 的 Java 生成 Play 应用程序时,我可以看到生成的控制器方法 (Application.index) 不是静态的.
此外,在以下文档页面中,控制器方法不是静态的:
https://www.playframework.com/documentation/2.4.x/JavaActions
这很令人困惑,因为了解每个请求是否由 Controller 实例处理(即是否可以使用状态)是非常基础的,我认为这应该在关于 Controller/Actions 比没有解释它的当前文档(上面的链接页面)。
关于依赖注入的文档在 "Dependency injecting controllers" 部分提到了 "static routes generator" 涉及静态和非静态方法的主题,但我认为应该更好地解释它,包括代码示例。
如果 Play 团队中有人正在阅读这个问题,那么请在上面的链接页面中添加一些信息,例如,请务必提及(如果我的理解是正确的话)在以前版本的 Play 中,控制器方法是静态的对于那些版本,你永远不应该在字段中存储状态,但在以后的版本中(从版本 x 开始?)每个请求都由控制器的一个实例处理,因此可以使用状态(例如框架注入的构造函数参数)。
还请提供有关与静态控制器方法一起使用的注入以及每个请求一个实例注入有状态控制器实例的代码示例。
依赖注入页面中的 "Component lifecycle" 部分只提到 "components" 但我认为它也应该明确说明控制器生命周期及其注入,因为它是一个非常基础和重要的知识与所有开发人员清楚地沟通,以避免因对是否有状态的误解而导致错误。
Is each web request handled by a new instance of a Play controller class, i.e. can a controller store state in fields such as services injected into the controller constructor? (where in the documentation is it explained?)
据我所知,控制器默认是单例对象。这没有明确记录,但暗示控制器实例被重用。见 migration guide for Playframework 2.4:
The injected routes generator also supports the @ operator on routes, but it has a slightly different meaning (since everything is injected), if you prefix a controller with @, instead of that controller being directly injected, a JSR 330 Provider for that controller will be injected. This can be used, for example, to eliminate circular dependency issues, or if you want a new action instantiated per request.
此外,检查 this commend made by James Roper(Play 核心提交者)控制器是否为单例:
Not really - if using Guice, each time the controller is injected into something, a new instance will be created by default. That said, the router is a singleton, and so by association, the controllers it invokes are singleton. But if you inject a controller somewhere else, it will be instantiated newly for that component.
这表明默认情况下是在响应请求时重用控制器实例,如果您希望每个请求都有一个新操作,则需要使用迁移指南中描述的语法。但是...因为我更倾向于证明和尝试事情而不是仅仅相信,我创建了一个简单的控制器来检查该声明:
package controllers
import play.api._
import play.api.mvc._
class Application extends Controller {
def index = Action {
println(this)
Ok(views.html.index("Your new application is ready."))
}
}
对此操作执行多个请求会为所有请求打印相同的对象 identity。但是,如果我在我的路线上使用 @ 运营商,我开始为每个请求获得不同的 identities 。所以,是的,控制器默认是(某种)单例。
Has the Play framework changed since earlier versions (and if so, at what version?) regarding if controllers are stateful instances or stateless controllers with static methods?
默认情况下,Play一直提倡无状态控制器,你可以在the project homepage:
看到
Play is based on a lightweight, stateless, web-friendly architecture.
那没有改变。因此,您不应使用控制器的 fields/properties 来保存在 time/requests 期间发生变化的数据。相反,只需使用控制器的 fields/properties 来保持对其他也是无状态的 components/services 的引用。
Where can you see code examples about how the framework injects services into a controller instance when stateful controller is used and example of how to inject services into a static controller method?
关于代码示例,Lightbend templates repository 是去处。以下是一些在控制器级别使用依赖注入的示例:
- https://github.com/adrianhurt/play-api-rest-seed
- https://github.com/knoldus/playing-reactive-mongo
- https://github.com/KyleU/boilerplay
不支持静态方法的依赖注入,这就是为什么 Playframework 剧照提供 old apis 与静态方法一起使用。这里的经验法则是:在 DI 和静态方法之间进行选择。尝试同时使用两者只会给您的应用程序带来复杂性。
好的,谢谢 marcospereira。
我现在还确认您确实为每个请求获得了控制器的不同实例(不同的 toString 值,在控制器方法中可以是 printed/logged)。
对于那些感兴趣的人,解决方案(为每个请求获取不同的控制器实例 class)是使用以下示例:
GET / @controllers.Application.index()
而不是以下内容:
GET / controllers.Application.index()
在文件中"conf/routes"
并且还使用以下内容:
routesGenerator := InjectedRoutesGenerator
而不是以下内容:
routesGenerator := StaticRoutesGenerator
在文件中"build.sbt"
关于 Play 具有 "stateless" 架构的说法:
也许我错了,但据我了解术语,"stateless" 意味着 Web 服务器不存储请求之间的任何状态?
"stateless" 一词并不意味着控制器实例不能使用字段,例如注入到构造函数中。
如果注入的对象作为字段存储在控制器中,则该字段是控制器的 "state"。
因此,即使您使用 "InjectedRoutesGenerator" 和“@”前缀来获取 "stateful" 控制器实例,注入的 "state" 也仅存储在一个请求中,因此您仍然可以说框架本身是 "stateless" 因为服务器不存储多个请求之间的任何状态。
如果我对 Play 是无状态的有什么误解,请纠正我。
我的问题是关于 Java 的 Play 框架中控制器的生命周期,如果控制器是有状态实例或使用静态方法的无状态,以及如何在控制器代码中使用依赖注入。
是否每个 Web 请求都由 Play 控制器的新实例处理 class,即控制器是否可以将状态存储在注入控制器构造函数的服务等字段中? (在文档中的哪个位置进行了解释?)
关于控制器是有状态实例还是使用静态方法的无状态控制器,Play 框架自早期版本以来是否发生了变化(如果是,是什么版本?)?
您在哪里可以看到有关在使用有状态控制器时框架如何将服务注入控制器实例的代码示例以及如何将服务注入静态控制器方法的示例?
关于后者,即注入静态方法,我想这要么必须是框架将添加的方法的参数,要么如果不可能的话,您可能不得不从内部使用服务定位器方法例如实例化一个 Guice 模块 class,然后在静态控制器方法中使用 "injector.getInstance"。
下一页的 "Dependency injecting controllers" 部分涉及此主题:
https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection
但是,它没有显示代码如何实际将服务注入控制器实例(但可能与其他 "components" 相同的方式,即使用 @Inject 注释),当然它目前没有显示如何将 DI 与静态控制器方法结合使用。
我对这些事情感到困惑,因为我没有找到明确说明我的问题的文档,而且我还在一本 Play 书中(从 2013 年开始)读到控制器方法应该被编程为无状态并且控制器方法应该保持静止。
但是,当现在使用激活器为具有最新 Play 版本 (2.4.6) 的 Java 生成 Play 应用程序时,我可以看到生成的控制器方法 (Application.index) 不是静态的. 此外,在以下文档页面中,控制器方法不是静态的: https://www.playframework.com/documentation/2.4.x/JavaActions
这很令人困惑,因为了解每个请求是否由 Controller 实例处理(即是否可以使用状态)是非常基础的,我认为这应该在关于 Controller/Actions 比没有解释它的当前文档(上面的链接页面)。
关于依赖注入的文档在 "Dependency injecting controllers" 部分提到了 "static routes generator" 涉及静态和非静态方法的主题,但我认为应该更好地解释它,包括代码示例。
如果 Play 团队中有人正在阅读这个问题,那么请在上面的链接页面中添加一些信息,例如,请务必提及(如果我的理解是正确的话)在以前版本的 Play 中,控制器方法是静态的对于那些版本,你永远不应该在字段中存储状态,但在以后的版本中(从版本 x 开始?)每个请求都由控制器的一个实例处理,因此可以使用状态(例如框架注入的构造函数参数)。
还请提供有关与静态控制器方法一起使用的注入以及每个请求一个实例注入有状态控制器实例的代码示例。
依赖注入页面中的 "Component lifecycle" 部分只提到 "components" 但我认为它也应该明确说明控制器生命周期及其注入,因为它是一个非常基础和重要的知识与所有开发人员清楚地沟通,以避免因对是否有状态的误解而导致错误。
Is each web request handled by a new instance of a Play controller class, i.e. can a controller store state in fields such as services injected into the controller constructor? (where in the documentation is it explained?)
据我所知,控制器默认是单例对象。这没有明确记录,但暗示控制器实例被重用。见 migration guide for Playframework 2.4:
The injected routes generator also supports the @ operator on routes, but it has a slightly different meaning (since everything is injected), if you prefix a controller with @, instead of that controller being directly injected, a JSR 330 Provider for that controller will be injected. This can be used, for example, to eliminate circular dependency issues, or if you want a new action instantiated per request.
此外,检查 this commend made by James Roper(Play 核心提交者)控制器是否为单例:
Not really - if using Guice, each time the controller is injected into something, a new instance will be created by default. That said, the router is a singleton, and so by association, the controllers it invokes are singleton. But if you inject a controller somewhere else, it will be instantiated newly for that component.
这表明默认情况下是在响应请求时重用控制器实例,如果您希望每个请求都有一个新操作,则需要使用迁移指南中描述的语法。但是...因为我更倾向于证明和尝试事情而不是仅仅相信,我创建了一个简单的控制器来检查该声明:
package controllers
import play.api._
import play.api.mvc._
class Application extends Controller {
def index = Action {
println(this)
Ok(views.html.index("Your new application is ready."))
}
}
对此操作执行多个请求会为所有请求打印相同的对象 identity。但是,如果我在我的路线上使用 @ 运营商,我开始为每个请求获得不同的 identities 。所以,是的,控制器默认是(某种)单例。
Has the Play framework changed since earlier versions (and if so, at what version?) regarding if controllers are stateful instances or stateless controllers with static methods?
默认情况下,Play一直提倡无状态控制器,你可以在the project homepage:
看到Play is based on a lightweight, stateless, web-friendly architecture.
那没有改变。因此,您不应使用控制器的 fields/properties 来保存在 time/requests 期间发生变化的数据。相反,只需使用控制器的 fields/properties 来保持对其他也是无状态的 components/services 的引用。
Where can you see code examples about how the framework injects services into a controller instance when stateful controller is used and example of how to inject services into a static controller method?
关于代码示例,Lightbend templates repository 是去处。以下是一些在控制器级别使用依赖注入的示例:
- https://github.com/adrianhurt/play-api-rest-seed
- https://github.com/knoldus/playing-reactive-mongo
- https://github.com/KyleU/boilerplay
不支持静态方法的依赖注入,这就是为什么 Playframework 剧照提供 old apis 与静态方法一起使用。这里的经验法则是:在 DI 和静态方法之间进行选择。尝试同时使用两者只会给您的应用程序带来复杂性。
好的,谢谢 marcospereira。 我现在还确认您确实为每个请求获得了控制器的不同实例(不同的 toString 值,在控制器方法中可以是 printed/logged)。
对于那些感兴趣的人,解决方案(为每个请求获取不同的控制器实例 class)是使用以下示例:
GET / @controllers.Application.index()
而不是以下内容:
GET / controllers.Application.index()
在文件中"conf/routes" 并且还使用以下内容:
routesGenerator := InjectedRoutesGenerator
而不是以下内容:
routesGenerator := StaticRoutesGenerator
在文件中"build.sbt"
关于 Play 具有 "stateless" 架构的说法: 也许我错了,但据我了解术语,"stateless" 意味着 Web 服务器不存储请求之间的任何状态? "stateless" 一词并不意味着控制器实例不能使用字段,例如注入到构造函数中。 如果注入的对象作为字段存储在控制器中,则该字段是控制器的 "state"。 因此,即使您使用 "InjectedRoutesGenerator" 和“@”前缀来获取 "stateful" 控制器实例,注入的 "state" 也仅存储在一个请求中,因此您仍然可以说框架本身是 "stateless" 因为服务器不存储多个请求之间的任何状态。 如果我对 Play 是无状态的有什么误解,请纠正我。