简体   繁体   中英

How can I pass an instance to a ServiceInjector trait with scala?

I'm following the advice from 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

But I'm very new to Scala and trying to work out how I can use the following pattern for dependency injection, when the Guice Module itself needs references to instances passed in from elsewhere.

But since traits can't have constructors, and neither can the Companion Object it looks like I'm screwed?

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)
}

I realize that the object is being initialized when it's first used, and that is after I have a copy of the instances to pass to OModule, but I can't seem to find a way to pass them in to the object.

Since I'm using Scala I am not a fan anymore of using DI frameworks since Scala has natively DI-like support already. This is called the Cake Pattern. There are plenty resources available on this, like this blogpost from Cake Solutions .

Both at ScalaDays 2014 and Devoxx 2014 Dick Wall also presented about a more lightweight DI solution which he called the Parfait Pattern. Both talks can be viewed on Parleys.com

If you really want to use a DI framework, Scaldi is a nice looking Scala framework utilising Scala features, but of course you can also keep on using Spring or Guice.

I'm not sure about this:

@Inject val toBeInjected: AnotherClass = toBeInjected

wouldn't work in my experience. It needs to be a var rather than val and the initial value null .

@Inject var toBeInjected: AnotherClass = null

I created a demo on GitHub which is the Play-Scala template with the index method changed as follows:

class Application extends Controller {

  @Inject var ws: WSClient = null

  def index = Action.async {
    ws.url("http://google.com").get.map(r => Ok(r.body))
  }

}

which worked well. That injected to a field, rather than as a constructor parameter. The same technique can be used with traits .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM