【问题标题】:How can I pass an instance to a ServiceInjector trait with scala?如何使用 scala 将实例传递给 ServiceInjector 特征?
【发布时间】:2015-07-07 00:23:50
【问题描述】:

我正在听从 com.googlegroups.google-guice http://markmail.org/message/ljnhl6rstverrxuj 的建议

Well, it's actually almost as referred to you in the link from the other answer:

http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/

class MyClient {
  @Inject val toBeInjected: AnotherClass = toBeInjected // !!
}

trait ServiceInjector {
  ServiceInjector.inject( this )
}

object ServiceInjector {
  private val injector = Guice.createInjector( Array[Module]( new YourModule ) )
  def inject( obj: AnyRef ) = injector.injectMembers( obj )
}

Usage:

val client = new MyClient with ServiceInjector

or:

class InjectedMyClient extends MyClient with ServiceInjector

但我对 Scala 还是很陌生,并试图弄清楚如何在 Guice 模块本身需要引用从其他地方传入的实例时使用以下模式进行依赖注入。

但是由于特质不能有构造函数,伴侣对象也不能,看起来我被搞砸了?

package au.id.rleach.overmind.guice

import com.google.inject.{Provides, Guice, Binder, Module}
import org.slf4j.Logger
import org.spongepowered.api.service.ServiceManager
import org.spongepowered.api.world.TeleportHelper
import org.spongepowered.api.{GameRegistry, Game}
import org.spongepowered.api.plugin.PluginManager
import org.spongepowered.api.scoreboard.ScoreboardBuilder
import org.spongepowered.api.service.event.EventManager

class OModule(val game: Game, val logger: Logger, val pluginManager: PluginManager, val serviceManager: ServiceManager, val eventManager: EventManager, val gameRegistry: GameRegistry, val teleportHelper: TeleportHelper) extends Module {

  override def configure(binder: Binder): Unit = {
    binder.bind(classOf[Game]).toInstance(game)
    binder.bind(classOf[Logger]).toInstance(logger)
    binder.bind(classOf[PluginManager]).toInstance(pluginManager)
    binder.bind(classOf[ServiceManager]).toInstance(serviceManager)
    binder.bind(classOf[EventManager]).toInstance(eventManager)
    binder.bind(classOf[GameRegistry]).toInstance(gameRegistry)
    binder.bind(classOf[TeleportHelper]).toInstance(teleportHelper)
    //bind(classOf[File]).annotatedWith(new ConfigDirAnnotation(true)).toInstance(Loader.instance.getConfigDir)
  }
}

trait ServiceInjector {
  ServiceInjector.inject(this)
}

object ServiceInjector {
  private val injector = Guice.createInjector(
//####
    new OModule()//compilation error.
//####
  )
  def inject(obj: AnyRef) = injector.injectMembers(obj)
}

我意识到该对象在第一次使用时正在初始化,那是在我将实例的副本传递给 OModule 之后,但我似乎找不到将它们传递给对象的方法。

【问题讨论】:

    标签: scala guice


    【解决方案1】:

    由于我使用的是 Scala,因此我不再喜欢使用 DI 框架,因为 Scala 已经原生支持类似 DI 的功能。这被称为蛋糕模式。这方面有很多可用的资源,比如blogpost from Cake Solutions

    在 ScalaDays 2014 和 Devoxx 2014 上,Dick Wall 还介绍了一种更轻量级的 DI 解决方案,他称之为 Parfait 模式。这两场演讲都可以在 Parleys.com 上查看

    如果你真的想使用 DI 框架,Scaldi 是一个使用 Scala 特性的漂亮 Scala 框架,当然你也可以继续使用 Spring 或 Guice。

    【讨论】:

    • 我使用 Guice 的原因是为了 Java 兼容性,我已经通过我的世界服务器模组 SpongeAPI 的 guice 注入获取实例。
    【解决方案2】:

    我不确定:

    @Inject val toBeInjected: AnotherClass = toBeInjected
    

    根据我的经验是行不通的。它需要是var 而不是val 和初始值null

    @Inject var toBeInjected: AnotherClass = null
    

    我创建了一个demo on GitHub,它是Play-Scala 模板,其中index 方法更改如下:

    class Application extends Controller {
    
      @Inject var ws: WSClient = null
    
      def index = Action.async {
        ws.url("http://google.com").get.map(r => Ok(r.body))
      }
    
    }
    

    效果很好。即注入到字段中,而不是作为构造函数参数。 traits 可以使用相同的技术。

    【讨论】:

    • 注入 val 的工作正常,这不是我遇到问题的部分。问题是我无法传入模块需要的实例,并且我无权访问用于获取插件类中的实例的注入器。我最终为对象中的模块创建了一个设置器,但我也不太喜欢这个解决方案,所以希望在堆栈溢出时发布更好的内容。
    • @Inject val toBeInjected: AnotherClass = toBeInjected toBeInjected 是什么?如果您要获得注射器并自己注射,为什么要使用@Inject
    猜你喜欢
    • 2015-06-07
    • 1970-01-01
    • 2021-03-24
    • 2012-01-14
    • 1970-01-01
    • 2020-12-05
    • 2020-09-29
    • 1970-01-01
    相关资源
    最近更新 更多