Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Dependency injection in scala

8.789 Aufrufe

Veröffentlicht am

Evaluation of DI frameworks in context of using them with Play!

Veröffentlicht in: Technologie, Business
  • COnsidering the module on page 19, how would the injection itself look like?
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • Hi Ashish, I cannot say about Scaldi because I have no experience there. What I saw in its website, Scaldi basically 'provides service locator pattern' via Injector. I don't like a pattern because you cannot test in isolation, I mean just class itself. But ... I think this is not an issue with Akka, while you cannot test Actor in isolation (I mean plain class itself) either. You are still dependent from ActorSystem itself and Without TestKit you cannot test it. Thus my decision would be based on comparison if the Scaldi provides you more features out of box as Guice or not. Next I would question my self if I need to inject just 'services' aka non-actor classes or even actors itself. You can still look-up actors from ActorSystem, which is basically same as 'locator pattern' mentioned above, thus I suppose you need to inject 'services' as plain old scala/java classes. For that purpose is Guice pretty straight-forward solution see: https://github.com/rocketraman/activator-akka-scala-guice and http://www.typesafe.com/activator/template/activator-akka-scala-guice But it does not provide you injection of Actors out of box which Scaldi (at least by documentation) does (see website). Take a look on, too: http://letitcrash.com/post/55958814293/akka-dependency-injection - Akka team guidelines, even a bit outdated https://github.com/giabao/akka-guice - another library mixing Guice and Akka together, providing actor injection too http://eng.kifi.com/guicing-up-scala-actors/ - blog post using Akka and Guice together, wiring http://eng.kifi.com/testing-with-akka-and-guice/ - blog post using Akka and Guice together, testing I hope this will help :) Btw: take a look on http://di-in-scala.github.io/#akka too. It uses MacWire, which I like :)
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • I'm working on Akka-Scala project where I need DI feature. Whether I should go for Guice or Scaldi, if I have these two choices? Mostly I'll be having actors, DB conn, FSM DI and few more depending on use case.
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier

Dependency injection in scala

  2. 2. AGENDA 1. Introduction 2. Evaluation criteria 3. Covered approaches/frameworks Spring Spring-Scala CDI Guice SubCut Cake 4. Recommendations
  3. 3. INTRODUCTION CATEGORIZATION OF APPROACHES Pure Scala approaches: Subcut, Cake Mixed Java/Scala approaches: Spring-Scala, Guice Pure Java aproaches: Spring, CDI
  4. 4. INTRODUCTION WHY JAVA DI FRAMEWORKS AT ALL Reason 1: Important for existing Java-based projects, when you need to mix Java and Scala Reason 2: Mature, proven solutions
  5. 5. EVALUATION CRITERIA 1. As much as possible idiomatic approach minimal usage of: vars, annotations, special configuration files ideal case pure Scala 2. Simple testing Integration testing Unit testing too 3. Good fit with Play! 4. No steep learning curve
  6. 6. EVALUATION CRITERIA Symbols used in evaluation (+) pros (-) cons (±) it depends
  8. 8. SPRING 1. Relies heavily on annotations (-) 2. External configuration file is needed (-) 3. Differences are minimal in relation to Java (±) 4. Immutability possible via constructor injection (+) 5. Setter injection requires additional work in Scala (±) 6. Popular well-designed Java framework (+) 7. More than just DI (±) 8. Various testing possibilities (±)
  9. 9. SPRING SPECIALS SETTER INJECTION or @org.springframework.stereotype.Controller class Translate extends Controller { @BeanProperty @(Autowired @beanSetter) var translator: Translator = _ ... } @org.springframework.stereotype.Controller class Translate extends Controller { private var translator: Translator = _ @Autowired def setTranslator(translator: Translator): Unit = this.translator = translator ... }
  10. 10. SPRING-SCALA 1. No annotations (+) 2. Wiring in code, no external configuration file (+) 3. Work in progress (-) 4. Immutability via contructor injection (+) 5. Spring under the hood (+) 6. Provides DSL to use Spring templates (±) 7. Various testing possibilities (±)
  11. 11. SPRING-SCALA SPECIALS TEMPLATES Improvements: functions, Options, manifests ConnectionFactory connectionFactory = ... JmsTemplate template = new JmsTemplate(connectionFactory); template.send("queue", new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createTextMessage("Hello World"); } }); val connectionFactory : ConnectionFactory = ... val template = new JmsTemplate(connectionFactory) template.send("queue") { session: Session => session.createTextMessage("Hello World") }
  12. 12. SPRING-SCALA SPECIALS XML CONFIGURATION class Person(val firstName: String, val lastName: String) { ... } <beans> <bean id="firstName" class="java.lang.String"> <constructor-arg value="John"/> </bean> <bean id="lastName" class="java.lang.String"> <constructor-arg value="Doe"/> </bean> </beans> class PersonConfiguration extends FunctionalConfiguration { importXml("classpath:/names.xml") val john = bean() { new Person(getBean("firstName"), getBean("lastName")) } }
  13. 13. SPRING-SCALA SPECIALS CONFIGURATION COMPOSITION You can use also traits for composition abstract class PersonConfiguration extends FunctionalConfiguration { val firstName: String val lastName: String bean() { new Person(firstName, lastName) } } class JohnDoeConfiguration extends PersonConfiguration { val firstName = singleton() { "John" } val lastName = singleton() { "Doe" } }
  14. 14. SPRING-SCALA SPECIALS PROFILES, INIT AND DESTROY class DataSourceConfiguration extends FunctionalConfiguration { profile("dev") { bean("dataSource") { new BasicDataSource() } init { // Set up properties } destroy { _.close() } } profile("prod") { bean("dataSource") { val dataSource = new OracleDataSource() // Set up properties dataSource } } }
  15. 15. CDI THE ONLY SOLUTION I DIDN'T TRY BECAUSE OF ITS LIMITS 1. Java EE Standard (JSR-299), part of every JEE6 compiliant container (±) 2. Relies heavily on annotations (-) 3. Only Singleton and Dependent scoped beans are injected as direct dependecies (-) 4. Proxy and ThreadLocal magic behind, doesn't work well with actors (-) 5. Mulitple implementations (±) 6. Various testing possibilities (±)
  16. 16. CDI LIMITS Various scopes: singleton, prototype (dependent), session, request, application Only singleton and dependent are injected directly Other scopes use proxies and thread locals Restriction on proxied classes: 1. Default constructor => no immutablity 2. No final classes and methods => Scala uses some in beckground implicitly
  17. 17. GOOGLE GUICE 1. Few annotations needed (±) 2. Only DI nothing else, leaner, easier (+) 3. Wiring in code, no external configuration file (+) 4. Immutability via contructor injection (+) 5. Scala DSL for bindings (+) 6. Easy testing (+)
  18. 18. GOOGLE GUICE SPECIALS PLAIN VANILLA GUICE Scala DSLs remove unnecessary classOf calls SBT dependencies class TranslationModule extends AbstractModule { def configure() { bind( classOf[Translator] ).to( classOf[FrenchTranslator] ) } } // Two options "com.tzavellas" % "sse-guice" % "0.7.1" "net.codingwell" %% "scala-guice" % "3.0.2"
  19. 19. GOOGLE GUICE SPECIALS INJECTION AND TESTING Anytime you can inject members using any arbitrary module. Relevant for setter injection. It is possible to override production module with another module in tests. Use ` instead of ' val runner = ... injector.injectMembers(runner) val m = Modules 'override' new ProductionModule 'with' new TestModule val injector = Guice createInjector m
  20. 20. SUBCUT 1. No annotations (+) 2. Wiring in code, no external configuration file (+) 3. Pure Scala library (+) 4. Intrusive code (-) 5. Actually service locator pattern and not DI (-) 6. Limited testing (-)
  21. 21. SUBCUT BINDING OPTIONS Example directly from SubCut website object SomeConfigurationModule extends NewBindingModule (module => { import module._ // optional but convenient - allows use of bind inst ead of module.bind bind [X] toSingle Y bind [Z] toProvider { codeToGetInstanceOfZ() } bind [A] toProvider { implicit module => new AnotherInjectedClass(par am1, param2) } // module singleton bind [B] to newInstanceOf [Fred] // create a new instance of Fred every time - Fred require injection bind [C] to moduleInstanceOf [Jane] // create a module scoped singlet on Jane that will be used bind [Int] idBy PoolSize to 3 // bind an Int identified by Pool Size to constant 3 bind [String] idBy ServerURL to "http://escalatesoft.com" })
  22. 22. SUBCUT LESS INTRUSIVE OPTION Normal definition of component Using AutoInjectable Sad news, it needs compiler plugin (macros in next versions) class SomeServiceOrClass(param1: String, param2: Int) (implicit val bindingModule: BindingModule) extends SomeTrait with Injectable { ... } class SomeServiceOrClass(param1: String, param2: Int) extends SomeTrait with AutoInjectable { ... }
  23. 23. CAKE PATTERN 1. Dependencies are checked in compile time, statically typed, immutable (+) 2. No library needed, uses only Scala language features (+) 3. Wiring in code, no external configuration file (+) 4. Uses advanced features of Scala, not easy to grasp (-) 5. Easy testing (+)
  24. 24. CAKE PATTERN EXPLANATION Definition of module/component // Module or Component trait Translation { // Services it provides def translator: Translator // Service interface with multiple implementations trait Translator { def translate(what: String): String } }
  25. 25. CAKE PATTERN EXPLANATION Implementation of component, relies on inharitance trait FrenchTranslation extends Translation { // Singleton instance override val translator = new FrenchTranslator // Implementation of service class FrenchTranslator extends Translator { def translate(what: String): String = {...} } }
  26. 26. CAKE PATTERN EXPLANATION Expressing dependency and usage, relies on self-type annotations trait Translate extends Controller { this: Translation => // Dependency def greet(name: String) = Action { // Usage of service Ok(views.html.greet(translator.translate(s"Hello $name!"))) } }
  27. 27. CAKE PATTERN EXPLANATION Binding, relies on mixins of traits object Translate extends Translate with FrenchTranslation
  28. 28. RECOMMENDATIONS WHEN TO USE (JAVA FRAMEWORKS) Spring (definitely w/ Spring-Scala) 1. When you need more than DI 2. When you need to intergate with Java code 3. When you know Spring well CDI 1. Only in JEE compiliant container, when your code depends on container services Guice 1. When you want to do only DI and do it well 2. When you need to integrate with Java code
  29. 29. RECOMMENDATIONS WHEN TO USE (SCALA DI) SubCut 1. When you want to be hipster and rant with a new library 2. When you want pure Scala solution Cake 1. Wnen you need additional type safety 2. When you want pure Scala solution 3. When you want very cohesive components/modules
  30. 30. RECOMMENDATIONS USAGE EXAMPLES Java/Scala mixed project => Spring or Guice Scala standalone project => Guice or Cake Play! project => Guice or Cake Domain or algorithm => Cake
  31. 31. RECOMMENDATIONS VERY SUBJECTIVE RANKING Category Spring CDI Guice SubCut Cake Idiomatic ** * ** *** *** Simple testing *** * *** * *** Good fit with Play! *** * *** ** *** No steep learning curve ** ** *** *** * Java integration *** *** *** n/a n/a