DI in Play 2.4
Compile time
Dependency Injection
with macwire
Yann Simon
Dependency Injection
Runtime
VS
Compile Time
Runtime vs compile time DI
●
Runtime
✔
Support Lifecycle (start / stop)
●
Compile time
✔
Dependency graph checked by compi...
source:
http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
Compile time DI
●
With the cake pattern
– Talk “Structure your Play application with the cake
pattern (and test it)”
●
Sli...
DI with constructor parameters
class Dependency1
class Dependency2 {
def parse(input: String): Unit =
println(s"parse '$in...
Singleton or not
// singleton
val dep1 = new Dependency1
val dep2 = new Dependency2
val service = new Service(dep1, dep2)
...
val or lazy val
val dep1 = new Dependency1
val service = new Service(dep1, dep2)
val dep2 = new Dependency2
java.lang.Null...
Complex dependency tree
lazy val dep1 = new Dependency1
lazy val dep2 = new Dependency2
lazy val dep3 = new Dependency3
la...
With macwire
import com.softwaremill.macwire._
lazy val dep1 = wire[Dependency1]
lazy val dep2 = wire[Dependency2]
lazy va...
macwire
●
Macwire resolves dependencies based on the
type
– Compile error when ambiguous
– No good idea to have a String a...
Macwire
●
https://github.com/adamw/macwire
●
Other features
– Accessing wired dynamically
– Interceptors
– Qualifiers
Integration of macwire with Play
●
Play 2.3
– Everything checked at compile time, expect...
routing... :(
●
Play 2.4
– Eve...
Macwire interceptor
●
Ex: monitor performance of ws calls:
– MonitoringInterceptor
lazy val videoGateway: VideoGateway = l...
Integration of macwire with Play 2.4
●
build.sbt:
libraryDependencies ++= Seq(
"com.softwaremill.macwire" %% "macros" %
"1...
Test application for IT tests
val context = ApplicationLoader.createContext(
new Environment(new File("."), ApplicationLoa...
The End
Questions?
Nächste SlideShare
Wird geladen in …5
×

Compile time dependency injection in Play 2.4 with macwire

3.294 Aufrufe

Veröffentlicht am

Compile time dependency injection in Playframework 2.4 with macwire

Veröffentlicht in: Technologie
0 Kommentare
11 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
3.294
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
234
Aktionen
Geteilt
0
Downloads
13
Kommentare
0
Gefällt mir
11
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Compile time dependency injection in Play 2.4 with macwire

  1. 1. DI in Play 2.4 Compile time Dependency Injection with macwire Yann Simon
  2. 2. Dependency Injection Runtime VS Compile Time
  3. 3. Runtime vs compile time DI ● Runtime ✔ Support Lifecycle (start / stop) ● Compile time ✔ Dependency graph checked by compiler ✔ No runtime overhead
  4. 4. source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
  5. 5. Compile time DI ● With the cake pattern – Talk “Structure your Play application with the cake pattern (and test it)” ● Slides: http://de.slideshare.net/yann_s/play-withcake-export2 ● Video: http://www.ustream.tv/recorded/42775808 ● With constructor parameters
  6. 6. DI with constructor parameters class Dependency1 class Dependency2 { def parse(input: String): Unit = println(s"parse '$input' with '$this'") } class Service(dep1: Dependency1, dep2: Dependency2) { def parse(input: String): Unit = dep2.parse(input) } val dep1 = new Dependency1 val dep2 = new Dependency2 val service = new Service(dep1, dep2)
  7. 7. Singleton or not // singleton val dep1 = new Dependency1 val dep2 = new Dependency2 val service = new Service(dep1, dep2) // one instance per call val dep1 = new Dependency1 def dep2 = new Dependency2 def service = new Service(dep1, dep2)
  8. 8. val or lazy val val dep1 = new Dependency1 val service = new Service(dep1, dep2) val dep2 = new Dependency2 java.lang.NullPointerException lazy val dep1 = new Dependency1 lazy val service = new Service(dep1, dep2) lazy val dep2 = new Dependency2
  9. 9. Complex dependency tree lazy val dep1 = new Dependency1 lazy val dep2 = new Dependency2 lazy val dep3 = new Dependency3 lazy val dep4 = new Dependency4 lazy val dep5 = new Dependency5(dep3, dep4) lazy val dep6 = new Dependency6(dep2, dep4) lazy val dep7 = new Dependency7(dep5, dep6) lazy val service = new Service(dep1, dep2, dep3, dep4, dep7)
  10. 10. With macwire import com.softwaremill.macwire._ lazy val dep1 = wire[Dependency1] lazy val dep2 = wire[Dependency2] lazy val dep3 = wire[Dependency3] lazy val dep4 = wire[Dependency4] lazy val dep5 = wire[Dependency5] lazy val dep6 = wire[Dependency6] lazy val dep7 = wire[Dependency7] lazy val service = wire[Service] And that's all!
  11. 11. macwire ● Macwire resolves dependencies based on the type – Compile error when ambiguous – No good idea to have a String as dependency ;)
  12. 12. Macwire ● https://github.com/adamw/macwire ● Other features – Accessing wired dynamically – Interceptors – Qualifiers
  13. 13. Integration of macwire with Play ● Play 2.3 – Everything checked at compile time, expect... routing... :( ● Play 2.4 – Everything checked at compile time! – https://github.com/yanns/TPA/pull/1/files ● Demo
  14. 14. Macwire interceptor ● Ex: monitor performance of ws calls: – MonitoringInterceptor lazy val videoGateway: VideoGateway = logDuration(wire[VideoGateway]) lazy val logDuration = MonitoringInterceptor.logDuration [debug] duration - 15ms for gateways.VideoGateway#top() [debug] duration - 5ms for gateways.PlayerGateway#findPlayer(2) [debug] duration - 7ms for gateways.PlayerGateway#findPlayer(1) [debug] duration - 4ms for gateways.PlayerGateway#findPlayer(3) [debug] duration - 23ms for services.TopVideoService#topVideos()
  15. 15. Integration of macwire with Play 2.4 ● build.sbt: libraryDependencies ++= Seq( "com.softwaremill.macwire" %% "macros" % "1.0.1", "com.softwaremill.macwire" %% "runtime" % "1.0.1") routesGenerator := play.routes.compiler.InjectedRoutesGenerator ● Customer loader in application.conf: play.application.loader=globals.TBAApplicationLo ader ● Custom loader: package globals import controllers.Assets import play.api.ApplicationLoader.Context import play.api._ import play.api.libs.ws.ning.NingWSComponents import play.api.routing.Router import router.Routes class TBAApplicationLoader extends ApplicationLoader { override def load(context: Context): Application = { Logger.configure(context.environment) (new BuiltInComponentsFromContext(context) with TBAComponents).application } } trait TBAComponents extends BuiltInComponents // standard play components with NingWSComponents // for wsClient with TBAApplication { import com.softwaremill.macwire._ lazy val assets: Assets = wire[Assets] lazy val router: Router = wire[Routes] withPrefix "/" }
  16. 16. Test application for IT tests val context = ApplicationLoader.createContext( new Environment(new File("."), ApplicationLoader.getClass.getClassLoader, Mode.Test)) class TBAApplicationLoaderMock extends ApplicationLoader { override def load(context: Context): Application = { new BuiltInComponentsFromContext(context) with TBAComponents { override lazy val wsClient: WSClient = MockWS(SimulatedPlayerBackend.routes) }.application } } implicit val application = new TBAApplicationLoaderMock().load(context) val server = TestServer(9000, application) running(server) { WsTestClient.withClient { ws ⇒ val response = await(ws.url(s"http://localhost:9000/player/$playerId").get()) response.status shouldEqual OK } }
  17. 17. The End Questions?

×