Using and contributing to the next Guice

2,346 views
2,241 views

Published on

This overviews Guice and its successor Dagger in context of usage in NetflixOSS

Published in: Technology, Education
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,346
On SlideShare
0
From Embeds
0
Number of Embeds
20
Actions
Shares
0
Downloads
21
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide
  • Resources such as JSR-311 and JerseyHooks like Service Registration and Discovery, HealthCheck hooks etc
  • Using and contributing to the next Guice

    1. 1. Using and contributing to the next Guice Adrian Cole @adrianfcole #netflixoss http://www.linkedin.com/in/adrianforrestcole
    2. 2. •Introduction •Guice •Guice at Netflix •Dagger •Dagger at Netflix •Wrapping up
    3. 3. Adrian • cloud guy at Netflix • founded jclouds • focus on (small) libraries
    4. 4. thanks @jessewilson • Guice • javax.inject • Android Core Libraries • Dagger
    5. 5. •Introduction •Guice •Guice at Netflix •Dagger •Dagger at Netflix •Wrapping up
    6. 6. Wiring With Guice!
    7. 7. (cc) creative commons from flickr.com/photos/uscpsc/7894303566/
    8. 8. class Thermosiphon implements Pump { private final Heater heater; Thermosiphon(Heater heater) { this.heater = heater; } @Override public void pump() { if (heater.isHot()) { System.out.println("=> => pumping => =>"); } } }
    9. 9. class Thermosiphon implements Pump { private final Heater heater; @Inject Thermosiphon(Heater heater) { this.heater = heater; } ... } Declare Dependencies
    10. 10. class CoffeeMaker { @Inject Heater heater; @Inject Pump pump; ... } Declare Dependencies
    11. 11. class DripCoffeeModule extends AbstractModule { @Overrides void configure() { bind(Heater.class).to(ElectricHeater.class); bind(Pump.class).to(Thermosiphon.class); } } Satisfy Dependencies
    12. 12. class CoffeeApp { public static void main(String[] args) { Injector injector = Guice.createInjector( new DripCoffeeModule()); CoffeeMaker coffeeMaker = injector.getInstance(CoffeeMaker.class); coffeeMaker.brew(); } } Build the Injector
    13. 13. •Introduction •Guice •Guice at Netflix •Dagger •Dagger at Netflix •Wrapping up
    14. 14. Netflix uses lots of Guice • Governator – Governate (verb) to wire together an app so that it implicitly bootstraps and exposes its lifecycle. • Karyon – Karyonate (verb) unpronouncable… so – Blueprint for a web app or REST service
    15. 15. Governator Bootstrap • Extends Guice – classpath scanning and automatic binding – lifecycle management – configuration to field mapping – field validation – parallelized object warmup • Some overlap with Apache Onami
    16. 16. class DieselHeater implements Heater { ... @PostConstruct void startEngine() { // mmm… exhaust with coffee.. } } Define @PostConstruct
    17. 17. class CoffeeApp { public static void main(String[] args) { Injector injector = LifeCycleInjector.createInjector( new DripCoffeeModule()); CoffeeMaker coffeeMaker = injector.getInstance(CoffeeMaker.class); coffeeMaker.brew(); } } Build the Injector
    18. 18. Karyon • Web Service Blueprint – Extends Governator, Guice Servlet – Built-in Admin Console – Pluggable Web Resources – Cloud-Ready hooks @Application has @Components Usually has a HealthCheckHandler
    19. 19. @Component(disableProperty = “killswitch”) class DieselHeater implements Heater { ... @PostConstruct void startEngine() { // mmm… exhaust with coffee.. } } Define @Component
    20. 20. appName.properties com.netflix.karyon.server.base.packages= com.foo.appName.components Check config
    21. 21. A Cloud Native Open Source Platform @adrianfcole #netflixoss More?
    22. 22. •Introduction •Guice •Guice at Netflix •Dagger •Dagger at Netflix •Wrapping up
    23. 23. Dagger Slides by Jesse Wilson from Square A fast dependency injector for Android and Java.
    24. 24. •Dagger –Motivation –Using Dagger –Inside Dagger
    25. 25. Motivation for Dependency Injection • Decouple concrete from concrete • Uniformity
    26. 26. Dependency Injection Choices • PicoContainer • Spring • Guice • javax.inject
    27. 27. (cc) creative commons from flickr.com/photos/getbutterfly/6317955134/
    28. 28. (cc) creative commons from flickr.com/photos/wikidave/2988710537/
    29. 29. We still love you, Froyo • Eager vs. lazy graph construction • Reflection vs. codegen
    30. 30. typicalprogrammer.com/?p=143 “I didn’t really expect anyone to use [git] because it’s so hard to use, but that turns out to be its big appeal. No technology can ever be too arcane or complicated for the black t- shirt crowd.” –Linus Torvalds
    31. 31. No black t-shirt necessary
    32. 32. (cc) creative commons from flickr.com/photos/mike_miley/5969110684/
    33. 33. • Know everything at build time. • Easy to see how dependencies are used & satisfied
    34. 34. Motivation for Dagger • It's like Guice, but with speed instead of features • Simple • Predictable also...
    35. 35. •Dagger –Motivation –Using Dagger –Inside Dagger
    36. 36. Directed Acyclic Graph DAGger.
    37. 37. (cc) creative commons from flickr.com/photos/uscpsc/7894303566/
    38. 38. class Thermosiphon implements Pump { private final Heater heater; Thermosiphon(Heater heater) { this.heater = heater; } @Override public void pump() { if (heater.isHot()) { System.out.println("=> => pumping => =>"); } } }
    39. 39. class Thermosiphon implements Pump { private final Heater heater; @Inject Thermosiphon(Heater heater) { this.heater = heater; } ... } Declare Dependencies
    40. 40. class CoffeeMaker { @Inject Heater heater; @Inject Pump pump; ... } Declare Dependencies
    41. 41. @Module(injects = CoffeeMakerApp.java) class DripCoffeeModule { @Provides Heater provideHeater() { return new ElectricHeater(); } @Provides Pump providePump(Thermosiphon pump) { return pump; } } Satisfy Dependencies
    42. 42. class CoffeeApp { public static void main(String[] args) { ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule()); CoffeeMaker coffeeMaker = objectGraph.get(CoffeeMaker.class); coffeeMaker.brew(); } } Build the Graph
    43. 43. Neat features • Lazy<T> • Module overrides • Multibindings
    44. 44. class GridingCoffeeMaker { @Inject Lazy<Grinder> lazyGrinder; public void brew() { while (needsGrinding()) { // Grinder created once and cached. Grinder grinder = lazyGrinder.get() grinder.grind(); } } } Lazy<T>
    45. 45. @Module( includes = DripCoffeeModule.class, injects = CoffeeMakerTest.class, overrides = true ) static class TestModule { @Provides @Singleton Heater provideHeater() { return Mockito.mock(Heater.class); } } Module Overrides
    46. 46. @Module class TwitterModule { @Provides(type=SET) SocialApi provideApi() { ... } } @Module class GooglePlusModule { @Provides(type=SET) SocialApi provideApi() { ... } } ... @Inject Set<SocialApi> Multibindings
    47. 47. •Dagger –Motivation –Using Dagger –Inside Dagger
    48. 48. Graphs!
    49. 49. Creating Graphs • Compile time – annotation processor • Runtime – generated code loader – reflection
    50. 50. Using Graphs • Injection • Validation • Graphviz!
    51. 51. But how? • Bindings have names like “com.squareup.geo.LocationMonitor” • Bindings know the names of their dependencies, like “com.squareup.otto.Bus”
    52. 52. final class CoffeeMaker$InjectAdapter extends Binding<CoffeeMaker> { private Binding<Heater> f0; private Binding<Pump> f1; public CoffeeMaker$InjectAdapter() { super("coffee.CoffeeMaker", ...); } public void attach(Linker linker) { f0 = linker.requestBinding("coffee.Heater", coffee.CoffeeMaker.class); f1 = linker.requestBinding("coffee.Pump", coffee.CoffeeMaker.class); } public CoffeeMaker get() { coffee.CoffeeMaker result = new coffee.CoffeeMaker(); injectMembers(result); return result; } public void injectMembers(CoffeeMaker object) { object.heater = f0.get(); object.pump = f1.get(); } public void getDependencies(Set<Binding<?>> bindings) { bindings.add(f0); bindings.add(f1); } }
    53. 53. Validation • Eager at build time • Lazy at runtime
    54. 54. dagger-compiler (cc) creative commons from flickr.com/photos/discover-central-california/8010906617
    55. 55. Built into javac Foolishly easy to use. Just put dagger-compiler on your classpath! javax.annotation.processing
    56. 56. It’s a hassle (for us) • Coping with prebuilt .jar files • Versioning • Testing
    57. 57. ... and it’s limited (for you) • No private or final field access • Incremental builds are imperfect • ProGuard
    58. 58. ... but it’s smoking fast! (for your users) • Startup time for Square Wallet on one device improved from ~5 seconds to ~2 seconds
    59. 59. Different Platforms are Different • HotSpot • Android • GWT
    60. 60. HotSpot: Java on the Server • The JVM is fast • Code bases are huge
    61. 61. Android • Battery powered • Garbage collection causes jank • Slow reflection, especially on older devices • Managed lifecycle
    62. 62. GWT • Code size really matters • Compiler does full-app optimizations • No reflection. github.com/tbroyer/sheath
    63. 63. API Design in the GitHub age Forking makes it easy to stay small & focused
    64. 64. public @interface Inject {} public @interface Named { String value() default ""; } public interface Provider { T get(); } public @interface Qualifier {} public @interface Scope {} public @interface Singleton {} javax.inject
    65. 65. public interface Lazy<T> { T get(); } public interface MembersInjector<T> { void injectMembers(T instance); } public final class ObjectGraph { public static ObjectGraph create(Object... modules); public ObjectGraph plus(Object... modules); public void validate(); public void injectStatics(); public <T> T get(Class type); public <T> T inject(T instance); } public @interface Module { Class[] injects() default { }; Class[] staticInjections() default { }; Class[] includes() default { }; Class addsTo() default Void.class; boolean overrides() default false; boolean complete() default true; boolean library() default true; } public @interface Provides { enum Type { UNIQUE, SET } Type type() default Type.UNIQUE; } dagger
    66. 66. •Introduction •Guice •Guice at Netflix •Dagger •Dagger at Netflix •Wrapping up
    67. 67. PORTABLE CONTROL OF DNS CLOUDS
    68. 68. @Provides @Singleton Route53 route53(Feign feign, Route53Target target) { return feign.newInstance(target); } Dependencies are HTTP Targets
    69. 69. Portable implementations class Route53ZoneApi implements ZoneApi { @Inject Route53 route53; ... }
    70. 70. •Introduction •Guice •Guice at Netflix •Dagger •Dagger at Netflix •Wrapping up
    71. 71. • Still the best choice for many apps • Broad ecosystem and stable core • May soon be able to mix & match with Dagger Guice
    72. 72. • Great for libraries • Extension averse, feature conservative • Friendly forks Dagger
    73. 73. Takeaway Dagger is a leaner version of Guice, suitable for libraries. Fork-friendly doesn’t mean don’t collaborate. http://square.github.io/dagger/ https://groups.google.com/forum/#!forum/dagger-discuss http://www.linkedin.com/in/adrianforrestcole @adrianfcole #netflixoss

    ×