【问题标题】:Scala play Guice injectionScala玩Guice注入
【发布时间】:2016-09-04 00:39:01
【问题描述】:

我正在使用 scala play 2.5,但在尝试在我的一个控制器中注入对象时出现以下错误。 我正在使用 Play 提供的默认注入框架 Guice。

    ProvisionException: Unable to provision, see the following errors: 
    1) No implementation for services.MyService was bound. 
    while locating services.MyService for parameter 0 at controllers.MyController.<init>(MyController.scala:12) 
    while locating controllers.MyController for parameter 3 at router.Routes.<init>(Routes.scala:55) 
    while locating router.Routes 
    while locating play.api.inject.RoutesProvider while locating play.api.routing.Router for parameter 0 at play.api.http.JavaCompatibleHttpRequestHandler.<init>(HttpRequestHandler.scala:200) 
    while locating play.api.http.JavaCompatibleHttpRequestHandler 
    while locating play.api.http.HttpRequestHandler for parameter 4 at play.api.DefaultApplication.<init>(Application.scala:221) at play.api.DefaultApplication.class(Application.scala:221) 
while locating play.api.DefaultApplication 
    while locating play.api.Application

这里是控制器:

package controllers

import services.MyService

class MyController @Inject()(myService: MyService, val messagesApi: MessagesApi) extends Controller with I18nSupport {

    def someFunctionThatUsesMyService(url: String) = Action {}
}

这是我要注入的服务:

package services

import javax.inject._

trait MyService {
    def op(param1: String, param2: String): Boolean
}

@Singleton
class BasicMyService extends MyService {
    override def op(param1: String, param2: String): Boolean = true
}

这就是我使用它的方式:

@Singleton
class HomeController @Inject() extends Controller {

  /**
   * Create an Action to render an HTML page with a welcome message.
   * The configuration in the `routes` file means that this method
   * will be called when the application receives a `GET` request with
   * a path of `/`.
   */
  def index = Action {
    //Ok(views.html.index("Your new application is ready."))
    Redirect(routes.MyController.someFunctionThatUsesMyService(Some(routes.OtherController.welcomePage().url)))
  }

}

【问题讨论】:

    标签: scala playframework dependency-injection guice


    【解决方案1】:

    您应该在 Service trait 中添加 ImplementedBy 注释

    package services
    
    import javax.inject._
    
    @ImplementedBy(classOf[BasicMyService])
    trait MyService {
        def op(param1: String, param2: String): Boolean
    }
    
    @Singleton
    class BasicMyService extends MyService {
        override def op(param1: String, param2: String): Boolean = true
    }
    

    【讨论】:

    • 如何为 MockedMyService 扩展 MyService 以进行测试?加载文件不会自动将 BasicMyService 绑定到它吗?
    • 为什么需要多一层抽象?为什么不直接将具体实现注入控制器并在需要时在测试中模拟它们?
    【解决方案2】:

    你可以尝试直接注入服务吗,为什么需要那层虚拟特征?所有东西都必须开箱即用,无需任何额外编码。你总是可以微调你的外部部门。请参见下面的示例。

    这是一些代码

    控制器:

    class MyController @Inject()(service: SomeConcreteService) extends Controller { /** just use service.anyMethod here */ }
    

    服务:

    @Singleton
    class SomeConcreteService @Inject()(otherStuff: OtherStuffConcrete){
    /** otherStuff will be also injected */
        def mySuperServiceMethod:={ "Hey!" }
    }
    

    测试:

    class MyControllerTest extends PlaySpec with OneAppPerSuite with MockitoSugar {
    
        // do it this way if you want framework to provide controller instance
        private val myController = app.injector.instanceOf[MyController]
    
        // or mock external deps and build controller on your own
        val externalService = mock[SomeConcreteService]
        val handMadeController = new MyController(externalService)
    
        "My controller" should{
            "do its best " in {
                val response = call(handMadeController.doStuff, FakeRequest())
    
                status(response) mustBe OK
    
                contentAsString(response) must include("Best controller")
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 1970-01-01
      • 2012-08-10
      相关资源
      最近更新 更多