簡體   English   中英

如何將參數注入 Scala 中的類/特征方法

[英]How to inject parameters into a class/trait method in Scala

我的 Play Scala (2.5x, 2.11.11) 應用程序中有一個代碼,到目前為止運行良好(它基於以下鏈接: https : //fizzylogic.nl/2016/11/27/authorize-訪問您的播放應用程序使用動作構建器和動作功能/ )。 但現在我需要將另一個類實例傳遞給 ApplicationAuthorizationHandler 類(注意:在我的代碼中,我使用 Guice DI 將參數注入類構造函數)。

當前代碼:

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 =>
...
}

所需代碼:

class ApplicationAuthorizationHandler @Inject() (userService: UserService)
   extends AuthorizationHandler {
   ...
   // userService is used here
}

但是由於 ApplicationAuthorizationHandler 的實例是在 trait AuthorizationCheck 中實例化的,所以我無法將 UserService 實例注入其中。 我在所有控制器中都混合了這個特性,所以我想保持相同的方式,除非有更好的方法(並且必須有)。 首先,有沒有辦法直接注入類/特征方法? 或者,有沒有一種方法可以讓我不在特征 AuthorizationCheck 中實例化 ApplicationAuthorizationHandler 並在控制器內部運行時傳遞它? 或者其他方式?

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 =>
     ...
   }
}

當然,您需要提供一個模塊來將AuthorizationHandler綁定到ApplicationAuthorizationHandler

import play.api.inject._

class AuthorizationHandlerModule extends SimpleModule(
  bind[AuthorizationHandler].to[ApplicationAuthorizationHandler]
)

當然, ApplicationAuthorizationHandler可以注入自己的依賴項。 您可以在我們的文檔中查看更多詳細信息

在很多情況下,你不能使用 guice 的@Inject方法。 當 trait 和 actor 內部需要依賴時,這是真的。

我在這些情況下使用的方法是將注入器放在一個對象中

object Injector {
  val injector = Guice.createInjector(new ProjectModule())
}

由於上述內容位於對象內部,因此您可以從任何地方訪問它。 (它就像一個單身人士)。

現在在您需要用戶服務時在您的特征或演員中

trait Foo {
   lazy val userService = Injector.injector.getInstance(classOf[UserService])
}

不要忘記將變量設為惰性,因為您希望在注入器已經創建后盡可能晚地創建實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM