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