当前位置: 首页 > 面试题库 >

是否每个Play框架Web请求都使用新的依赖项注入控制器实例处理,但是静态控制器方法又如何呢?

雍俊远
2023-03-14
问题内容

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

每个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实例处理(即是否可以使用状态)是非常基础的,所以我认为应该在关于Controller /
Actions的页面上比当前更好地记录这一点。文档(上面的链接页面)没有对其进行解释。

关于依赖注入的文档在“依赖注入控制器”一节中提到了“静态路由生成器”,触及了关于静态和非静态html" target="_blank">方法的主题,但是我认为应该更好地解释它,包括代码示例。

如果Play小组中的某人正在阅读此问题,请在上面的链接页面中添加一些信息,例如,请务必提及(如果我的理解是正确的)在Play的先前版本中,控制器方法是静态的,对于您使用的这些版本,应该永远不要将状态存储在字段中,但是在更高版本(从版本x开始)中,每个请求都由控制器的实例处理,因此可以使用状态(例如,框架注入的构造函数参数)。

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

依赖项注入页面中的“组件生命周期”部分仅提及“组件”,但我认为控制器生命周期及其注入也应该是明确的,因为这是与所有开发人员进行清晰沟通以避免漏洞的基础知识和重要知识由对是否有状态的误解引起的。


问题答案:

每个Web请求是否由Play控制器类的新实例处理,即控制器是否可以将状态存储在注入控制器构造函数的服务等字段中?(在文档中的什么地方说明了?)

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

注入的路由生成器还支持路由上的@运算符,但是它的含义略有不同(因为注入了所有内容),如果为控制器添加@前缀,而不是直接注入该控制器,则该控制器的JSR
330提供程序将被注射。例如,这可以用于消除循环依赖问题, 或者如果您希望每个请求实例化一个新操作

另外,请检查James
Roper(Play核心提交者)提出的有关控制器是否为单例的建议:

并非如此-如果使用Guice,则每次将控制器注入某个对象时,默认情况下都会创建一个新实例。也就是说,
路由器是单例,因此通过关联,它调用的控制器是单例 。但是,如果将控制器注入到其他位置,它将为该组件重新实例化。

这表明默认设置是在响应请求时重用控制器实例,如果要对每个请求执行新操作,则需要使用迁移指南中描述的语法。但是…由于我更倾向于证明和尝试事物而不是仅仅相信,所以我创建了一个简单的控制器来检查该语句:

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

}

对该操作执行多个请求将为所有发出的请求打印相同的对象 标识 。但是,如果我在路由上使用@运算符,则对于每个请求,我都会开始获得不同的 身份
。因此,是的, 默认情况下控制器是(某种)单例

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

默认情况下,Play始终提倡无状态控制器,如项目首页所示:

Play是基于轻量级, 无状态且 网络友好的体系结构。

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

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

关于代码示例,可以使用Activator模板存储库。下面是一些在控制器级别使用依赖注入的示例:

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

不支持使用静态方法进行依赖注入,这就是为什么Playframework剧照提供了旧的api以用于静态方法的原因。经验法则是:在DI和静态方法之间进行选择。尝试同时使用两者只会给您的应用程序带来复杂性。



 类似资料:
  • 我跟随播放2.6的Scala留档和创建非阻塞操作的示例代码,并遇到一些运行时问题。我已经使用Scala模板创建了一个新的Play应用程序()。 播放留档建议应该在新的控制器中工作的代码是(这段代码逐字取自播放留档页面,从我这里有一些额外的导入): 然后,根据使用其他线程池的文档,我定义了

  • 问题内容: 我仍然是Angularjs的新手。我想在控制器中动态注入服务(我创建的)的依赖项。 但是,当我对具有依赖项的服务进行编码时,出现此错误: 错误:未知提供程序:$ windowProvider <-$ window <-base64 这是控制器的代码。 此代码有效: 此代码不起作用: 另一个问题是服务与控制器位于同一模块中。如果模块具有依赖项,则无法使用(我的模块配置中具有$ route

  • 英文原文:http://emberjs.com/guides/controllers/dependencies-between-controllers/ 有时候,特别是在嵌套资源时,可能需要为两个控制器建立某种联系。以下面的路由为例: 1 2 3 4 5 App.Router.map(function() { this.resource("post", { path: "/posts/:po

  • 有没有可能使控制器依赖于他们的服务,而不是通过使用服务容器,而是通过纯粹的构造函数依赖注入? 我希望以这种方式编写控制器: 不幸的是,正如我所看到的,Symfony ControllerResolver不通过ServiceContainer而是通过简单的调用创建新的控制器实例。

  • 问题内容: 人们经常提到“依赖注入”和“控制反转”,这是使用Spring框架开发Web框架的主要优点。 如果可能的话,有人可以用一个简单的例子来解释它吗? 问题答案: 由于依赖注入, Spring有助于创建松耦合的应用程序。 在Spring中,对象定义其关联(依赖关系),而不必担心它们将如何获得这些依赖关系。Spring的责任是提供创建对象所需的依赖关系。 例如:假设我们有一个对象,并且它对对象有

  • 问题内容: 以下angular.ui模态示例显示了调用a ,该调用后来被创建为函数: 我有2个问题/问题: 文档建议以其他方式(由于缩小问题)创建控制器,例如: 但是,如果我像这样创建控制器,如何将其注入modalInstance? 我在这里调用的控制器不是Modal Instance控制器,而是我的global ,这是问题吗?我应该以某种方式继承loginCtrl还是从ModalInstance