Lightweight Dependency Injection Library

Created by  Oleg Ilyenko  @easyangel

Only 3 Main Concepts

1  Injector

A container for the bindings

3  Injectable

DSL for injection

inject [SomeClass]
... or this one ...

inject [Database] (identified by 'remote and by default new Riak)

Injector  and  Injectable

class OfficialMessageService(implicit inj: Injector)
          extends MessageService with Injectable {

  val officialGreeting =
    inject [String] (identified by "greeting.official")

  def getGreetMessage(name: String) =
    s"$officialGreeting, $name!"
and Module of course

class UserModule extends Module {
  bind [MessageService] to new OfficialMessageService

  binding identifiedBy "greeting.official" to "Welcome"


Lazy binding

bind [ActorSystem] to new ActorSystem
Non-lazy binding

bind [Server] toNonLazy new HttpServer
Provider binding

bind [Connection] toProvider inject[Database].getConnection

★ Something Special ★

Injector Composition

def tokenModule = new Module {
  bind [Tokens] to new TokenRepo(db = inject [Database])

def dbModule = new Module {
  bind [Database] to new Riak

def appModule = tokenModule :: dbModule
and then test it

def mocksModule = new Module {
  bind [Database] to new InMemoryDb

implicit val testModule = mocksModule :: appModule

Injector Types

  • Mutable Injectors
  • Immutable Injectors
  • Properties Injector
  • Play Configuration Injector
  • Create you own, it's easy

trait Injector {
  def getBinding(identifiers: List[Identifier]): Option[Binding]
  def getBindings(identifiers: List[Identifier]): List[Binding]

  // ...

Constructor  Injection

class TokenRepo(db: Database, metrics: Metrics) extends Tokens {
  // ...
injected macro

bind [Tokens] to injected [TokenRepo]
compiled to

bind [Tokens] to new TokenRepo(
  db = inject [Database],
  metrics = inject [Metrics])

Argument  Overrides

bind [Tokens] to injected [TokenRepo] (
  'db -> inject [Database] ('tokensOnly))
compiled to

bind [Tokens] to new TokenRepo(
  db = inject [Database] ('tokensOnly),
  metrics = inject [Metrics])



binding identifiedBy "intAdder" to
  ((a: Int, b: Int) => a + b)

binding identifiedBy "mapping" to Map(
  "scala" -> "",
  "play" -> "",
  "akka" -> ""

val intAdder = inject [(Int, Int) => Int]

val mapping = inject [Map[String, String]]


class UserModule extends Module {
  bind [MessageService] when (inDevMode or inTestMode) to
    new SimpleMessageService

  bind [MessageService] when inProdMode to
    new OfficialMessageService

def inDevMode(implicit inj: Injector) = {
  val mode = inject [Mode]
  Condition(mode == Dev)

Binding Lifecycle

class MyModule extends Module {
  bind [ActorSystem] to
    ActorSystem("ScaldiExample") destroyWith (_.shutdown())

  bind [Database] to new Mongo initWith (_.start())

implicit val injector = new MyModule

// do stuff ...



  • Extend almost any part of the library
    • Injector
    • Condition
    • Binding and BindingWithLifecycle
    • Identifier - create your own and define how they match
  • Type classes
    • CanCompose - defines how Injectors can be composed together
    • CanBeIdentifier

Create  a  Controller

Finally you can develop with classes and not singleton objects.

class Application(implicit inj: Injector)
          extends Controller with Injectable {

  val messageService = inject [MessageService]

  def index = Action {
      messageService.getGreetMessage("Test User")))

Then  Bind  it

class MyModule extends Module {
  binding to new Application

  bind [MessageService] to new OfficialMessageService

Define  Global

object Global extends GlobalSettings with ScaldiSupport {
  def applicationModule =
          new MyModule :: new SomeOtherModule

Configure  routes

Don't forget @

GET  /   @controllers.Application.index

Play  Extras


inject [Application]
inject [Mode]
inject [Configuration]

def applicationModule =
  new MyModule ::
    new ControllerInjector

bind [Thing] when (inDevMode or inTestMode or inProdMode) to
  new SomeThing
All configuration properties are also available as bindings

inject [String] (identified by "")
inject [Int] (identified by "db.port")

Akka  Injectable

  • injectActorProps
  • injectActorRef

class Receptionist(implicit inj: Injector)
    extends Actor with AkkaInjectable {

  val orderProcessorProps = injectActorProps [OrderProcessor]

  val priceCalculator = injectActorRef [PriceCalculator]

  def receive = {
    case PlaceOrder(userName, itemId, netAmount) =>
      val processor = context.actorOf(orderProcessorProps)
      // ...

Actor Ref  Factory

  • Should be implicitly available
    • ActorContext (within an actor)
    • ActorSystem (outside of actor)
  • Creates and configures an actor
    • Setups correct actor hierarchy
  • Integrates with Scaldi via Props

Actor  Bindings

Don't forget to bind with toProvider

class OrderModule extends Module {
  bind [ActorSystem] to ActorSystem("ScaldiExample")
    destroyWith (_.shutdown())

  binding toProvider new Receptionist
  binding toProvider new OrderProcessor
  binding toProvider new PriceCalculator

Present  &  Future

Play 2.4 & 3.0

  • Native DI mechanism
  • JSR 330


Thank you!