Dependecy Injection with examples in Guice
About me
SOLID
SOLID [1]
- Single Responsibility
- Open/Close
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
"Don't call us,
we'll call you"
[2]
Manual DI
Example
Simple Greeter
- Prints Greeting to stdout
- Has no tests
Goal: Have tests
DEMO
Guice
Injector
- Bullet One
- Bullet Two
- Bullet Three
https://devopedia.org/dependency-injection
import com.google.inject.Guice
object DateApp extends App {
val injector = Guice.createInjector()
val date = injector.getInstance(
classOf[java.util.Date]
)
println(date.toString)
}
[info] Running DateApp DateApp
Fri Dec 07 18:09:06 GMT 2018
Modules
- Bullet One
- Bullet Two
- Bullet Three
What happend when we inject abstract class?
trait FizzBuzz {
def fizzbuzz(number: Int): String
}
object AbstractApp extends App {
val injector = Guice.createInjector()
val fizzbuzz = injector.getInstance(
classOf[FizzBuzz]
)
println(fizzbuzz.fizzbuzz(15))
}
[error] (run-main-1) com.google.inject.ConfigurationException: Guice configuration errors:
[error]
[error] 1) No implementation for FizzBuzz was bound.
[error] while locating FizzBuzz
[error]
[error] 1 error
[error] com.google.inject.ConfigurationException: Guice configuration errors:
[error]
[error] 1) No implementation for FizzBuzz was bound.
[error] while locating FizzBuzz
[error]
[error] 1 error
object ModuleApp extends App {
val injector = Guice.createInjector(
FizzBazzModule
)
val fizzbazz = injector.getInstance(
classOf[FizzBazz]
)
println(fizzbazz.fizzbazz(15))
}
object FizzBazzModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[FizzBazz])
.to(classOf[DefaultFizzBazz])
}
}
class DefaultFizzBuzz extends FizzBuzz {
def fizzbuzz(number: Int): String = {
(number % 3, number % 5) match {
case (0, 0) => "fizzbuzz"
case (0, _) => "fizz"
case (_, 0) => "buzz"
case (_, _) => number.toString
}
}
}
[info] Running ModuleApp
fizzbazz
Injection Points
Injection points
- Constructors annotated with @Inject
- ----
- Fields annotated with @Inject
- Methods annotated with @Inject
- ----
- On demond injection
- Static injection
@Inject constructor
class ConstructorService
@Inject()(implicit ec: ExecitionContext){
// Some important methods
}
Providers
Providers
-
Logic on object creation
parameters are dig out from configuration with logic -
Object should be lazily created
allocation is costly and for some reason undesired -
Object creation is not based on new
akka's ActorRef - by system.actorOf -
Object creation/obtaining is be part of logic
connection to database Narrowing scope
we are obtain more detailed information
class SimpleModule extends AbstractModule {
@Provider
@Singleton
def utf8: Charset = {
Charset.forName("uft-8")
}
def configure(): Unit = {
//EMPTY
}
}
Inline providers in module definition
configuration.getOptional[Configuration](
s"$rootServices.$serviceName"
).orElse(
configuration.getOptional[Configuration](
s"$services.$serviceName"
)
).getOrElse(???)
Logic on creation
class ActorProvider
@Inject()(system: ActorSystem)
extends Provider[ActorRef] {
val ref = system.actorOf(Props[SomeAcotr])
override def get(): ActorRef = ref
}
Not based on new
class ConnectionExample
@Inject()(pool: Provider[Connection]){
def foo() = {
val connection = pool.get()
try {
// LOGIC here
} finally {
connection.close()
}
}
}
part of logic
Guice DI
Example
Example application Migrator
- Simple configuration module powered by file
- Have connection module which depends on address and port
- Migrator requires source configuration and target configuration
Code showcase
Hypothetical enhancement
Service Discavery
- Migrator should use service discovery
- Require only one paramter "discovery.bootstrap"
from command line parameter - Must be backword compatible -
may be not drop-in-replacement but changes should be minimal
DEMO
Docs
- Big Modular Java [3] - Google IO 2009
- Guice Wiki/Docs [4]
- Play guice bindings docs [5]
[1] https://en.wikipedia.org/wiki/SOLID
[2] http://wiki.c2.com/?HollywoodPrinciple
[3] https://www.youtube.com/watch?v=hBVJbzAagfs
[4] https://github.com/google/guice/wiki/Motivation
[5]https://www.playframework.com/documentation/2.6.x/ScalaDependencyInjection
DI with Guice
By bambucha
DI with Guice
- 718