Lightweight Scala Dependency Injection Library
Scaldi provides simple and elegant way to do dependency injection in Scala. By using expressive power of the Scala language it defines intuitive and idiomatic DSL for binding and injecting dependencies. It is very extensible library, so you can easily extend or customize almost any aspect of it. Some of the more unique Scaldi features are advanced module composition and conditional bindings which definitely will help you build all kinds of applications - from small command-line tools to big non-trivial web applications. Not to mention Scaldi also nicely integrates with Akka and Play.
Read the documentation and learn how you can use scaldi in your project.
Have any ideas or questions? There are many places where you can share and discuss them with others.
If you like the project and want to contribute, then there are plenty ways to do so. Any ideas, improvements or bugfixes are very welcome! Just fork it now and start implementing new cool stuff :)
Scaldi provides nice DSL for defining the bindings
class UserModule extends Module {
bind [MessageService] to new OfficialMessageService
binding identifiedBy "greeting.official" to "Welcome"
}
With neat DSL for injecting them
class OfficialMessageService(implicit inj: Injector)
extends MessageService with Injectable {
val officialGreeting =
inject [String] (identified by "greeting.official")
def getGreetMessage(name: String) =
s"$officialGreeting, $name!"
}
Scaldi also comes with the play framework support. Start using scaldi in a play application is as simple as configuring application loader and modules in application.conf:
play.application.loader = scaldi.play.ScaldiApplicationLoader
play.modules.enabled += modules.MyModule
play.modules.enabled += scaldi.play.ControllerInjector
Play now uses scaldi for dependency injection. From now on you can use scaldi to inject/bind bindings in your controllers as classes:
class Application(implicit inj: Injector) extends Controller with Injectable {
val messageService = inject [MessageService]
def index = Action {
Ok(views.html.index(messageService.getGreetMessage("Test User")))
}
}
You can easily split bindings between different modules and then compose them together
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
Scaldi provides an injected macro, which will inject all constructor arguments for you:
class TokenRepo(db: Database, met: Metrics) extends Tokens
def tokenModule = new Module {
bind [Tokens] to injected [TokenRepo]
}
You can even override injection mechanism on argument level:
def tokenModule = new Module {
bind [Tokens] to injected [TokenRepo] (
'met -> inject [Metrics] (identified by 'statsd))
}
Bindings may have lifecycle
class MyModule extends Module {
bind [ActorSystem] to
ActorSystem("ScaldiExample") destroyWith (_.shutdown())
bind [Database] to new Mongo initWith (_.start())
}
You can override bindings in order to mock parts of the application
def mocksModule = new Module {
bind [Database] to new InMemoryDb
}
implicit val testModule = mocksModule :: appModule
Bindings may have conditions associated with them
class UserModule extends Module {
bind [MessageService] when (inDevMode or inTestMode) to
new SimpleMessageService
bind [MessageService] when inProdMode to
new OfficialMessageService
}
and it's pretty straightforward to define new conditions
def inDevMode(implicit inj: Injector) = {
val mode = inject [Mode]
Condition(mode == Dev)
}
You can bind things like functions, lists or maps
binding identifiedBy "intAdder" to
((a: Int, b: Int) => a + b)
binding identifiedBy "mapping" to Map(
"scala" -> "http://scala-lang.org",
"play" -> "http://www.playframework.com",
"akka" -> "http://akka.io"
)
and then inject them
val intAdder = inject [(Int, Int) => Int]
val mapping = inject [Map[String, String]]
For seamless integration with other libraries or existing codebase.
def carModule = new Module {
bind [Car] to annotated [Convertible]
bind [Seat] identifiedBy qualifier [Drivers]
to annotated [DriversSeat]
}
implicit val injector =
carModule :: new OnDemandAnnotationInjector
val car = inject [Car]
Extend almost any part of the library, including
Some parts of the library are implemented as a type classes
With scaldi-akka you can inject ActorRefs and Props with injectActorProps and injectActorRef. Actors themselves can be defined in scaldi module.
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)
// ...
}
}
Just include scaldi dependency in the SBT build and you are ready to go:
libraryDependencies += "org.scaldi" %% "scaldi" % "0.5.8"
If you want to include scaldi into the play application, then scaldi-play would probably be more suitable for you
libraryDependencies += "org.scaldi" %% "scaldi-play" % "0.5.15"
Then you can just define application loader and your modules in the application.conf like this:
play.application.loader = scaldi.play.ScaldiApplicationLoader
play.modules.enabled += "modules.MyModule"
play.modules.enabled += "scaldi.play.ControllerInjector"
Play 2.3.x is still supported, you just need to use scaldi-play-23 instead:
libraryDependencies += "org.scaldi" %% "scaldi-play-23" % "0.5.6"
For the akka applications, scaldi-akka is the way to go:
libraryDependencies += "org.scaldi" %% "scaldi-akka" % "0.5.8"
If you are integrating or migrating existing apps that use JSR 330 annotations, then scaldi-jsr330 is the right choice:
libraryDependencies += "org.scaldi" %% "scaldi-jsr330" % "0.5.9"
After the initial setup you can read some documentation or look at scaldi presentation slides.
If you prefer more hands-on approach, then you may be interested in two example projects which you can play with: