每个 Play 框架 Web 请求是否都使用一个新的依赖注入控制器实例来处理,那么静态控制器方法呢? [英] Is each Play framework web request handled with a new dependency injected controller instance, but then what about static controller methods?

查看:22
本文介绍了每个 Play 框架 Web 请求是否都使用一个新的依赖注入控制器实例来处理,那么静态控制器方法呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是关于 Java Play 框架中控制器的生命周期,控制器是有状态的实例还是带有静态方法的无状态,以及如何在控制器代码中使用依赖注入.

每个 Web 请求是否由 Play 控制器类的新实例处理,即控制器是否可以将状态存储在注入到控制器构造函数中的服务等字段中?(在文档中的哪里解释?)

关于控制器是有状态实例还是具有静态方法的无状态控制器,Play 框架自早期版本(如果有,是什么版本?)是否有变化?

在哪里可以看到有关框架如何在使用有状态控制器时将服务注入控制器实例的代码示例以及如何将服务注入静态控制器方法的示例?

关于后者,即注入静态方法,我想这要么必须是框架将添加的方法的参数,要么如果不可能,您可能不得不在方法中使用服务定位器例如实例化一个 Guice 模块类,然后在静态控制器方法中使用injector.getInstance".

此主题在下一页的依赖注入控制器"部分中涉及:

https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection

然而,它没有显示如何将服务实际注入控制器实例的代码(但可能与其他组件"相同,即使用@Inject 注释),当然它目前没有显示如何使用 DI静态控制器方法.

我对这些事情感到困惑,因为我没有找到明确说明我的问题的文档,而且我还在 Play book(2013 年)中读到控制器方法应该被编程为无状态,控制器方法应该是静态的.

但是,当现在使用激活器为最新的 Play 版本 (2.4.6) 生成 Java Play 应用程序时,我可以看到生成的控制器方法 (Application.index) 不是静态的.此外,在以下文档页面中,控制器方法不是静态的:https://www.playframework.com/documentation/2.4.x/JavaActions

这令人困惑,因为了解每个请求是否由 Controller 实例处理(即是否可以使用状态)非常重要,我认为这应该在关于 Controller/Actions 的页面上更好地记录比没有解释它的当前文档(上面链接的页面).

关于依赖注入的文档在提到静态路由生成器"的依赖注入控制器"部分涉及静态和非静态方法的主题,但我认为应该更好地解释包括代码示例.

如果 Play 团队中有人正在阅读这个问题,那么请在上面链接的页面中添加一些信息,例如请提及(如果我的理解是正确的)在 Play 的先前版本中控制器方法是静态的,并且对于那些版本你永远不应该在字段中存储状态,但在以后的版本中(从版本 x 开始?)每个请求都由控制器的一个实例处理,因此可以使用状态(例如框架注入的构造函数参数).

还请提供有关与静态控制器方法一起使用的注入以及每个请求一个实例注入有状态控制器实例的代码示例.

依赖注入页面中的组件生命周期"部分只提到了组件",但我认为它也应该明确说明控制器的生命周期及其注入,因为与所有开发人员清楚地沟通是一个如此基础和重要的知识避免由于对是否有状态的误解而导致的错误.

解决方案

每个 Web 请求是否由 Play 控制器类的新实例处理,即控制器是否可以将状态存储在注入到控制器构造函数中的服务等字段中?(在文档中的哪里解释?)

据我所知,控制器默认是单例对象.这没有明确记录,但暗示控制器实例被重用.请参阅Playframework 2.4 迁移指南:

<块引用>

注入的路由生成器也支持路由上的@ 操作符,但它的含义略有不同(因为所有东西都被注入了),如果你在控制器前面加上@,而不是直接注入的控制器,一个 JSR 330 Provider for该控制器将被注入.例如,这可用于消除循环依赖问题,或者如果您希望每个请求实例化一个新操作.

另外,检查 这个由 James Roper 提出的推荐(播放核心提交者)关于控制器是否是单例的:

<块引用>

不是真的 - 如果使用 Guice,每次将控制器注入到某些东西中时,默认情况下都会创建一个新实例.也就是说,路由器是一个单例,因此通过关联,它调用的控制器是单例.但是如果你在其他地方注入一个控制器,它就会为那个组件重新实例化.

这表明默认是在响应请求时重用控制器实例,如果您希望每个请求有一个新操作,您需要使用迁移指南中描述的语法.但是...因为我更倾向于证明和尝试事情而不是仅仅相信,所以我创建了一个简单的控制器来检查该语句:

包控制器导入 play.api._导入 play.api.mvc._类应用程序扩展控制器{定义索引 = 动作 {打印(这个)好的(views.html.index(你的新应用程序已经准备好了."))}}

对此操作执行多个请求会为所有发出的请求打印相同的对象identity.但是,如果我在路由上使用 @ 操作符,我开始为每个请求获取不同的身份.所以,是的,控制器默认是(某种)单例.

<块引用>

关于控制器是有状态实例还是具有静态方法的无状态控制器,Play 框架自早期版本(如果有,是什么版本?)是否有变化?

默认情况下,Play 一直提倡无状态控制器,正如您在项目主页中所见::><块引用>

Play 基于轻量级、无状态、网络友好的架构.

那没有改变.因此,您不应使用控制器的字段/属性来保留随时间/请求而变化的数据.相反,只需使用控制器的字段/属性来保持对其他无状态组件/服务的引用.

<块引用>

在哪里可以看到有关框架如何在使用有状态控制器时将服务注入控制器实例的代码示例以及如何将服务注入静态控制器方法的示例?

关于代码示例,Lightbend 模板存储库 是您要去的地方.以下是在控制器级别使用依赖注入的一些示例:

  1. https://github.com/adrianhurt/play-api-rest-seed
  2. https://github.com/knoldus/playing-reactive-mongo
  3. https://github.com/KyleU/boilerplay

不支持使用静态方法的依赖注入,这就是为什么 Playframework 仍然提供 旧 apis 与静态方法一起使用.这里的经验法则是:在 DI 和静态方法之间进行选择.尝试同时使用两者只会给您的应用程序带来复杂性.

My questions are about the lifecycle of controllers in the Play framework for Java, if the controllers are stateful instances or stateless with static methods, and how to use dependency injection in the controller code.

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?)

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?

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?

Regarding the latter, i.e. injection into a static method I suppose that would either have to be a parameter to the method which the frameworks will add, or if not possible you maybe instead will have to use a service locator from within the method e.g. instantiate a Guice module class and then use "injector.getInstance" from within the static controller method.

This subject is touched in the section "Dependency injecting controllers" at the following page:

https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection

However, it does not show with code how to actually inject services into a controller instance (but probably the same way as other "components" i.e. with @Inject annotation) and certainly it does not currently show how to use DI with a static controller method.

I am confused about these things because I have not found documentation being clear about my questions, and I have also read in a Play book (from 2013) that the controller methods should be programmed as stateless and the controller methods should be static.

However, when now using activator for generating a Play application for Java with the latest Play version (2.4.6) I can see that the generated Controller method (Application.index) is NOT static. Also, at the following documentation page, the controller method is NOT static: https://www.playframework.com/documentation/2.4.x/JavaActions

This is confusing, and since it is VERY fundamental to understand whether or not each request is handled by a Controller instance or not (i.e. if state can be used) I think this should be better documented at the page about Controller/Actions than the current documentation (the above linked page) which is not explaining it.

The documentation about dependency injection touches the subject about static and non-static methods at the section "Dependency injecting controllers" mentioning "static routes generator" but I think it should be better explained including code examples.

If someone in the Play team is reading this question, then please add some information to the above linked pages, for example please do mention (if my understanding is correct) that in previous versions of Play the controller methods were static and for those versions you should never store state in fields, but in later versions (beginning from version x?) each request is handled by an instance of a controller and can therefore use state (e.g. constructor parameters injected by the framework).

Please also provide code examples about injection used with static controller methods and injection into stateful controller instances with one instance per request.

The section "Component lifecycle" in the dependency injection page only mentions "components" but I think it should also be explicit about the controller lifecycle and its injection, since it is such a fundamental and important knowledge to communicate clearly to all developers to avoid bugs caused by misunderstandings about being stateful or not.

解决方案

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?)

As far as I can tell, controllers are by default singleton objects. This is not clearly documented, but it is implied that controller instances are reused. See the 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.

Also, check this commend made by James Roper (Play core committer) about if controllers are singleton or not:

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.

This suggests that the default is to reuse controller instances when responding to requests and, if you want a new action per request, you need to use the syntax described in the migration guide. But... since I'm more inclined to prove and try things instead of just believe, I've created a simple controller to check that statement:

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."))
  }

}

Doing multiple requests to this action prints the same object identity for all the requests made. But, if I use the @ operator on my routes, I start to get different identities for each request. So, yes, controllers are (kind of) singletons by default.

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?

By default, Play had always advocated stateless controllers, as you can see at the project homepage:

Play is based on a lightweight, stateless, web-friendly architecture.

That had not changed. So, you should not use controllers' fields/properties to keep data that changes over time/requests. Instead, just use controllers' fields/properties to keep a reference to other components/services that are also stateless.

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?

Regarding code examples, Lightbend templates repository is the place to go. Here are some examples that use dependency injection at the controllers level:

  1. https://github.com/adrianhurt/play-api-rest-seed
  2. https://github.com/knoldus/playing-reactive-mongo
  3. https://github.com/KyleU/boilerplay

Dependency Injection with static methods is not supported, and that is why Playframework stills offers old apis to use with static methods. The rule of thumb here is: choose between DI and static methods. Trying to use both will just bring complexity to your application.

这篇关于每个 Play 框架 Web 请求是否都使用一个新的依赖注入控制器实例来处理,那么静态控制器方法呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆