簡體   English   中英

使用play.api.cache.Cache和編譯時依賴注入

[英]Using play.api.cache.Cache with compile time dependency injection

我正在嘗試將我的Pl​​ay應用程序從2.3.9遷移到2.4.3並使用編譯時依賴注入。 我在使用舊的全局Cache api對象( play.api.cache.Cache )時收到InstantiationException 我在我的組件中包含了EhCacheComponents (它提供了一個緩存實現),但似乎Play試圖直接實例化抽象CacheApi

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[InstantiationException: play.api.cache.CacheApi]]

<snip>

Caused by: java.lang.InstantiationException: play.api.cache.CacheApi
at java.lang.Class.newInstance(Class.java:427) ~[na:1.8.0_51]
at play.api.inject.NewInstanceInjector$.instanceOf(Injector.scala:49) ~[play_2.11-2.4.3.jar:2.4.3]
at play.api.inject.SimpleInjector$$anonfun$instanceOf$1.apply(Injector.scala:85) ~[play_2.11-2.4.3.jar:2.4.3]

我知道建議是使用新的依賴注入組件,但是文檔建議這應該仍然有效,並且我希望我的應用程序無需一次性更改即可運行。

這是一個簡化的應用程序,演示了這個問題:

class AppApplicationLoader extends ApplicationLoader {
  def load(context : play.api.ApplicationLoader.Context) : play.api.Application = {
    Logger.configure(context.environment)
    new AppComponents(context).application
  }
}

class AppComponents(context : play.api.ApplicationLoader.Context) extends BuiltInComponentsFromContext(context) with EhCacheComponents {
  lazy val assets = new controllers.Assets(httpErrorHandler)
  lazy val router: Router = new Routes(httpErrorHandler, assets, new controllers.TestController())
}

-

package controllers

class TestController extends Controller {
    def test = Action {
        Cache.getAs[String]("hello") map { result => 
            Ok(result)
        } getOrElse {
            Ok("not found")
        }
    }
}

組態:

# key, langs, etc. removed
play.application.loader = "AppApplicationLoader"
play.modules.enabled += "play.api.cache.EhCacheModule"

我怎樣才能做到這一點?

可以通過替換默認注入器並添加更多組件來實現此目的。 我想這不再是編譯時的DI(因為依賴關系現在正在運行時解析),但它確實有效。

擴展BuiltInComponents

trait AppComponents(context: Context) extends BuiltInComponents 
  with I18nComponents 
  with EhCacheComponents {

    // other dependencies (e.g. router, assets) here

    //need to add any other components here that you want to reference via the global APIs  - 
    //e.g. csrfConfig from CSRFComponents      
    override lazy val injector: Injector = new SimpleInjector(
      NewInstanceInjector
    ) + router + crypto + httpConfiguration + defaultCacheApi  + messagesApi
}

不幸的是你不能引用super.injector因為它是一個lazy val ,所以你不得不重新定義BuiltInComponents已有的BuiltInComponents ,這不是很好。 在將來升級Play時,檢查添加到基本定義的任何新組件是否都會復制到新實現中非常重要。

在我的實際應用程序中,我使用的是MacWire ,因此我編寫了一個自定義注入器:

class MacwireInjector(fallback: Injector, wired: Wired) extends Injector {

  /**
    * Get an instance of the given class from the injector.
    */
  def instanceOf[T](implicit ct: ClassTag[T]) = instanceOf(ct.runtimeClass.asInstanceOf[Class[T]])

  /**
    * Get an instance of the given class from the injector.
    */
   def instanceOf[T](clazz: Class[T]) = wired.lookup(clazz) match {
    case instance :: Nil => instance
    case Nil => fallback.instanceOf(clazz)
    case set => throw new RuntimeException(s"Multiple instances returned for $clazz: $set")
  }

  /**
    * Get an instance bound to the given binding key.
    */
  def instanceOf[T](key: BindingKey[T]) = instanceOf(key.clazz)
}

BuiltInComponents:

// probably need to do this otherwise MacWire finds two candidates from EhCacheComponents
lazy val cacheApi = defaultCacheApi

override lazy val injector: Injector = new MacwireInjector(NewInstanceInjector, wiredInModule(this))

或使用MacWire的默認注入器作為后備:

override lazy val injector: Injector = new SimpleInjector(
  new MacwireInjector(NewInstanceInjector, wiredInModule(this))
) + router + crypto + httpConfiguration

如果使用Compile Time依賴項注入,則應通過對象的參數傳遞依賴項:

class TestController(cache: CacheApi) extends Controller {
  ...
}

並在app loader中傳遞實現:

class AppComponents(context : play.api.ApplicationLoader.Context) extends BuiltInComponentsFromContext(context) with EhCacheComponents {
  lazy val assets = new controllers.Assets(httpErrorHandler)
  lazy val controller = new controllers.TestController(defaultCacheApi)
  lazy val router: Router = new Routes(httpErrorHandler, assets, controller)
}

暫無
暫無

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

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