我的问题是关于Play框架中Java控制器的生命周期,如果控制器是有状态实例或静态方法无状态,以及如何在控制器代码中使用依赖注入.
每个Web请求是否由Play控制器类的新实例处理,即控制器是否可以在诸如注入控制器构造函数的服务等字段中存储状态?
(在文档中的位置解释了吗?)
自早期版本(如果是,在什么版本?)后Play框架是否已更改,关于控制器是有状态实例还是静态方法的无状态控制器?
在哪里可以看到有关在使用有状态控制器时框架如何将服务注入控制器实例的代码示例以及如何将服务注入静态控制器方法的示例?
关于后者,即注入静态方法,我认为要么必须是框架将添加的方法的参数,要么如果不可能,你可能必须使用方法中的服务定位器,例如,实例化一个Guice模块类,然后在静态控制器方法中使用“injector.getInstance”.
在以下页面的“依赖注入控制器”部分中介绍了该主题:
https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection
但是,它没有用代码显示如何将服务实际注入到控制器实例中(但可能与其他“组件”相同,即使用@Inject注释)当然它当前没有显示如何使用静态控制器方法使用DI .
我对这些事情感到困惑,因为我没有发现文档清楚我的问题,而且我还在Play书(从2013年)中读到,控制器方法应该被编程为无状态,控制器方法应该是静态的.
但是,当现在使用激活器生成具有最新Play版本(2.4.6)的Java Play应用程序时,我可以看到生成的Controller方法(Application.index)不是静态的.
此外,在以下文档页面中,控制器方法不是静态的:
https://www.playframework.com/documentation/2.4.x/JavaActions
这是令人困惑的,因为了解每个请求是否由Controller实例处理是非常基础的(即,如果可以使用状态)我认为这应该在关于控制器/动作的页面上比当前更好地记录.文档(上面链接的页面)没有解释它.
有关依赖注入的文档在“依赖注入控制器”部分提到“静态路由生成器”时涉及静态和非静态方法的主题,但我认为应该更好地解释包括代码示例.
如果Play团队中有人正在阅读此问题,那么请在上面的链接页面中添加一些信息,例如请提及(如果我的理解是正确的)在以前版本的Play中控制器方法是静态的,对于那些版本你永远不应该在字段中存储状态,但在更高版本中(从版本x开始?),每个请求都由控制器的实例处理,因此可以使用状态(例如框架注入的构造函数参数).
还请提供有关静态控制器方法使用的注入和注入有状态控制器实例的代码示例,每个请求只有一个实例.
依赖注入页面中的“组件生命周期”部分仅提到“组件”,但我认为它也应该明确控制器生命周期及其注入,因为它是一个基本且重要的知识,可以清楚地与所有开发人员进行通信以避免错误由于对有状态与否的误解而引起的.
解决方法:
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(播放核心提交者)是否控制器是单身:
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."))
}
}
对此操作执行多个请求会为所有请求打印相同的对象标识.但是,如果我在我的路线上使用@运算符,我会开始为每个请求获得不同的身份.所以,是的,默认情况下,控制器是(有点)单例.
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.
那并没有改变.因此,您不应该使用控制器的字段/属性来保持随时间/请求而变化的数据.相反,只需使用控制器的字段/属性来保持对无状态的其他组件/服务的引用.
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?
关于代码示例,Activator 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和静态方法之间进行选择.尝试使用它们只会给您的应用程序带来复杂性.