Skip to content

Dependency Injection

laforge49 edited this page Nov 30, 2011 · 4 revisions

If you need to have a number of operations that can be accessed by many actors, dependency injection is the way to go. Dependency injection is done using the SystemServices object, which was previously covered in the discussion on AsyncMailbox. SystemServices is a composite actor, so we just need to add the operations we need as additional components. Lets start by looking at a component which supplies an "common" operation and its factory:

case class Today()

class Sayings(actor: Actor) extends Component(actor) {
  bind(classOf[Today], today)

  def today(msg: AnyRef, rf: Any => Unit) {
    rf("Today is the first day of the rest of your life.")
  }
}

class SayingsFactory extends ComponentFactory {
  override protected def instantiate(actor: Actor) = new Sayings(actor)
}

Now, assuming that the Sayings component is part of the SystemServices object, lets see how we would send a Today message to it:

case class SaySomething()

class SayIt extends Actor {
  bind(classOf[SaySomething], saySomething)

  def saySomething(msg: AnyRef, rf: Any => Unit) {
    systemServices(Today())(rf)
  }
}

Now for a bit of test code which creates and configures the SayIt actor and then sends a SaySomething message to it:

val systemServices = SystemServices(new SayingsFactory)
try {
  val sayIt = new SayIt
  sayIt.setExchangeMessenger(systemServices.newSyncMailbox)
  println(Future(sayIt, SaySomething()))
} finally {
  systemServices.close
}

There are two ways of providing an actor with access to the SystemServices object. (1) You can do it explicitly by calling the Actor.setSystemServices method or (2) you can assign a mailbox to the actor by calling Actor.setExchangeMessenger. In the latter case, the actor gets the default SystemServices object from the mailbox. If you call both methods, the value passed in the call to setSystemServices is always used.

When we created the SystemServices object, we added the Sayings component by passing its factory as an parameter. But what if we want to add more than one component? We have already seen in Factories and Components that the addDependency method can be used in a component factory to ensure the inclusion of other components. So at worst, we can just create a top-level component factory which creates multiple dependencies on the component factories of all the components that should be included in the SystemServices composite.

IOCTest

Clone this wiki locally