[英]How to inject parameters into a class/trait method in Scala
I have a code in my Play Scala (2.5x, 2.11.11) app which has been running just fine so far (it is based on the following link: https://fizzylogic.nl/2016/11/27/authorize-access-to-your-play-application-using-action-builders-and-action-functions/ ).我的 Play Scala (2.5x, 2.11.11) 应用程序中有一个代码,到目前为止运行良好(它基于以下链接: https : //fizzylogic.nl/2016/11/27/authorize-访问您的播放应用程序使用动作构建器和动作功能/ )。 But now I need to pass another class instance to ApplicationAuthorizationHandler class (NOTE: throughout my code I am using Guice DI for injecting parameters into class constructors).但现在我需要将另一个类实例传递给 ApplicationAuthorizationHandler 类(注意:在我的代码中,我使用 Guice DI 将参数注入类构造函数)。
Current code:当前代码:
class ApplicationAuthorizationHandler
extends AuthorizationHandler {
...
}
trait AuthorizationHandler {
...
}
trait AuthorizationCheck {
def authorizationHandler: AuthorizationHandler = new ApplicationAuthorizationHandler
object AuthenticatedAction extends ActionBuilder[RequestWithPrincipal] {
override def invokeBlock[A](request: Request[A], block: (RequestWithPrincipal[A]) => Future[Result]): Future[Result] = {
def unauthorizedAction = authorizationHandler.unauthorized(RequestWithOptionalPrincipal(None, request))
def authorizedAction(principal: Principal) = block(RequestWithPrincipal(principal, request))
authorizationHandler.principal(request).fold(unauthorizedAction)(authorizedAction)
}
}
}
//Example controller using this trait AuthorizationCheck
class MyController @Inject() extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
Desired code:所需代码:
class ApplicationAuthorizationHandler @Inject() (userService: UserService)
extends AuthorizationHandler {
...
// userService is used here
}
But since the instance of ApplicationAuthorizationHandler is instantiated inside trait AuthorizationCheck I can't inject UserService instance into it.但是由于 ApplicationAuthorizationHandler 的实例是在 trait AuthorizationCheck 中实例化的,所以我无法将 UserService 实例注入其中。 I am Mixin this trait with all controllers so would like to keep the same way unless there is a better way (and there must be).我在所有控制器中都混合了这个特性,所以我想保持相同的方式,除非有更好的方法(并且必须有)。 First, is there a way to inject directly into class/trait method ?首先,有没有办法直接注入类/特征方法? Alternatively, is there a way where I don't instantiate ApplicationAuthorizationHandler in trait AuthorizationCheck and pass it during run-time inside the controller ?或者,有没有一种方法可以让我不在特征 AuthorizationCheck 中实例化 ApplicationAuthorizationHandler 并在控制器内部运行时传递它? Or any other way ?或者其他方式?
A trait does not need to provide an implementation, so you can have something like: trait 不需要提供实现,所以你可以有类似的东西:
trait AuthorizationHandler {
...
}
class ApplicationAuthorizationHandler extends AuthorizationHandler {
...
}
trait AuthorizationCheck {
// just declaring that implementations needs to provide a
def authorizationHandler: AuthorizationHandler
object AuthenticatedAction extends ActionBuilder[RequestWithPrincipal] {
override def invokeBlock[A](request: Request[A], block: (RequestWithPrincipal[A]) => Future[Result]): Future[Result] = {
def unauthorizedAction = authorizationHandler.unauthorized(RequestWithOptionalPrincipal(None, request))
def authorizedAction(principal: Principal) = block(RequestWithPrincipal(principal, request))
authorizationHandler.principal(request).fold(unauthorizedAction)(authorizedAction)
}
}
}
// So, now this controller needs to provide a concrete implementation
// of "authorizationHandler" as declared by "AuthorizationCheck".
// You can do it by injecting a "AuthorizationHandler" as a val with
// name authorizationHandler.
class MyController @Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
}
And of course, you need to provide a module to bind AuthorizationHandler
to ApplicationAuthorizationHandler
:当然,您需要提供一个模块来将AuthorizationHandler
绑定到ApplicationAuthorizationHandler
:
import play.api.inject._
class AuthorizationHandlerModule extends SimpleModule(
bind[AuthorizationHandler].to[ApplicationAuthorizationHandler]
)
Of course, ApplicationAuthorizationHandler
can have its own dependencies injected.当然, ApplicationAuthorizationHandler
可以注入自己的依赖项。 You can see more details at our docs .您可以在我们的文档中查看更多详细信息。
There are many cases when you cannot use the @Inject
approach of guice.在很多情况下,你不能使用 guice 的@Inject
方法。 This is true when dependencies are needed inside of trait and also actors.当 trait 和 actor 内部需要依赖时,这是真的。
The approach I use in these cases is that I put my injector in a object我在这些情况下使用的方法是将注入器放在一个对象中
object Injector {
val injector = Guice.createInjector(new ProjectModule())
}
since the above is inside of an object, you can access it from anywhere.由于上述内容位于对象内部,因此您可以从任何地方访问它。 (its like a singleton). (它就像一个单身人士)。
Now inside your trait or an actor when you need the user service do现在在您需要用户服务时在您的特征或演员中
trait Foo {
lazy val userService = Injector.injector.getInstance(classOf[UserService])
}
Don't forget to make the variable lazy, because you want the instance to be created as late as possible when the injector has already been created.不要忘记将变量设为惰性,因为您希望在注入器已经创建后尽可能晚地创建实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.