Top Banner
Using and contributing to the next Guice Adrian Cole @adrianfcole #netflixoss http://www.linkedin.com/in/ adrianforrestcole
73

Using and contributing to the next Guice

May 27, 2015

Download

Technology

Adrian Cole

This overviews Guice and its successor Dagger in context of usage in NetflixOSS
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Using and contributing to the next Guice

Using and contributing to the next Guice

Adrian Cole@adrianfcole #netflixoss

http://www.linkedin.com/in/adrianforrestcole

Page 2: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 3: Using and contributing to the next Guice

Adrian• cloud guy at Netflix• founded jclouds• focus on (small) libraries

Page 4: Using and contributing to the next Guice

thanks @jessewilson

• Guice• javax.inject• Android Core Libraries• Dagger

Page 5: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 6: Using and contributing to the next Guice

Wiring With Guice!

Page 7: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/uscpsc/7894303566/

Page 8: Using and contributing to the next Guice

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 => =>"); } }}

Page 9: Using and contributing to the next Guice

class Thermosiphon implements Pump { private final Heater heater;

@Inject Thermosiphon(Heater heater) { this.heater = heater; } ...}

Declare Dependencies

Page 10: Using and contributing to the next Guice

class CoffeeMaker {

@Inject Heater heater; @Inject Pump pump; ...}

Declare Dependencies

Page 11: Using and contributing to the next Guice

class DripCoffeeModule extends AbstractModule {

@Overrides void configure() { bind(Heater.class).to(ElectricHeater.class);

bind(Pump.class).to(Thermosiphon.class); }}

Satisfy Dependencies

Page 12: Using and contributing to the next Guice

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

Page 13: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 14: Using and contributing to the next Guice

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

Page 15: Using and contributing to the next Guice

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

Page 16: Using and contributing to the next Guice

class DieselHeater implements Heater {

...

@PostConstruct void startEngine() {

// mmm… exhaust with coffee.. }}

Define @PostConstruct

Page 17: Using and contributing to the next Guice

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

Page 18: Using and contributing to the next Guice

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

Page 19: Using and contributing to the next Guice

@Component(disableProperty = “killswitch”)class DieselHeater implements Heater {

...

@PostConstruct void startEngine() {

// mmm… exhaust with coffee.. }}

Define @Component

Page 20: Using and contributing to the next Guice

appName.properties com.netflix.karyon.server.base.packages= com.foo.appName.components

Check config

Page 21: Using and contributing to the next Guice

A Cloud Native Open Source Platform

@adrianfcole #netflixoss

More?

Page 22: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 23: Using and contributing to the next Guice

Dagger

Slides by Jesse Wilson from Square

A fast dependency injector for Android and Java.

Page 24: Using and contributing to the next Guice

•Dagger

–Motivation

–Using Dagger

–Inside Dagger

Page 25: Using and contributing to the next Guice

Motivation for Dependency Injection

• Decouple concrete from concrete• Uniformity

Page 26: Using and contributing to the next Guice

Dependency InjectionChoices

• PicoContainer• Spring• Guice• javax.inject

Page 27: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/getbutterfly/6317955134/

Page 28: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/wikidave/2988710537/

Page 29: Using and contributing to the next Guice

We still love you, Froyo

• Eager vs. lazy graph construction• Reflection vs. codegen

Page 30: Using and contributing to the next Guice

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

Page 31: Using and contributing to the next Guice

No black t-shirt necessary

Page 32: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/mike_miley/5969110684/

Page 33: Using and contributing to the next Guice

• Know everything at build time.

• Easy to see how dependencies are used & satisfied

Page 34: Using and contributing to the next Guice

Motivation for Dagger

• It's like Guice, but with speed instead of features

• Simple• Predictable

also...

Page 35: Using and contributing to the next Guice

•Dagger

–Motivation

–Using Dagger

–Inside Dagger

Page 36: Using and contributing to the next Guice

DirectedAcyclicGraph

DAGger.

Page 37: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/uscpsc/7894303566/

Page 38: Using and contributing to the next Guice

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 => =>"); } }}

Page 39: Using and contributing to the next Guice

class Thermosiphon implements Pump { private final Heater heater;

@Inject Thermosiphon(Heater heater) { this.heater = heater; } ...}

Declare Dependencies

Page 40: Using and contributing to the next Guice

class CoffeeMaker {

@Inject Heater heater; @Inject Pump pump; ...}

Declare Dependencies

Page 41: Using and contributing to the next Guice

@Module(injects = CoffeeMakerApp.java)class DripCoffeeModule {

@Provides Heater provideHeater() { return new ElectricHeater(); }

@Provides Pump providePump(Thermosiphon pump) { return pump; }}

Satisfy Dependencies

Page 42: Using and contributing to the next Guice

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

Page 43: Using and contributing to the next Guice

Neat features

• Lazy<T>• Module overrides• Multibindings

Page 44: Using and contributing to the next Guice

class GridingCoffeeMaker {

@Inject Lazy<Grinder> lazyGrinder;

public void brew() {

while (needsGrinding()) { // Grinder created once and cached.

Grinder grinder = lazyGrinder.get()

grinder.grind(); } }}

Lazy<T>

Page 45: Using and contributing to the next Guice

@Module( includes = DripCoffeeModule.class,

injects = CoffeeMakerTest.class,

overrides = true ) static class TestModule {

@Provides @Singleton Heater provideHeater() { return Mockito.mock(Heater.class); }

}

Module Overrides

Page 46: Using and contributing to the next Guice

@Moduleclass TwitterModule { @Provides(type=SET) SocialApi provideApi() { ... }}@Moduleclass GooglePlusModule { @Provides(type=SET) SocialApi provideApi() { ... }}...@Inject Set<SocialApi>

Multibindings

Page 47: Using and contributing to the next Guice

•Dagger

–Motivation

–Using Dagger

–Inside Dagger

Page 48: Using and contributing to the next Guice

Graphs!

Page 49: Using and contributing to the next Guice

Creating Graphs

• Compile time– annotation processor

• Runtime– generated code loader– reflection

Page 50: Using and contributing to the next Guice

Using Graphs

• Injection• Validation• Graphviz!

Page 51: Using and contributing to the next Guice

But how?

• Bindings have names like“com.squareup.geo.LocationMonitor”

• Bindings know the names of their dependencies, like“com.squareup.otto.Bus”

Page 52: Using and contributing to the next Guice

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); }

}

Page 53: Using and contributing to the next Guice

Validation

• Eager at build time• Lazy at runtime

Page 54: Using and contributing to the next Guice

dagger-compiler

(cc) creative commons from flickr.com/photos/discover-central-california/8010906617

Page 55: Using and contributing to the next Guice

Built into javac

Foolishly easy to use. Just put dagger-compiler on your classpath!

javax.annotation.processing

Page 56: Using and contributing to the next Guice

It’s a hassle(for us)

• Coping with prebuilt .jar files• Versioning• Testing

Page 57: Using and contributing to the next Guice

... and it’s limited(for you)

• No private or final field access• Incremental builds are imperfect• ProGuard

Page 58: Using and contributing to the next Guice

... but it’s smoking fast!(for your users)

• Startup time for Square Wallet on one device improved from ~5 seconds to ~2 seconds

Page 59: Using and contributing to the next Guice

Different Platforms are Different

• HotSpot• Android• GWT

Page 60: Using and contributing to the next Guice

HotSpot:Java on the Server

• The JVM is fast• Code bases are huge

Page 61: Using and contributing to the next Guice

Android

• Battery powered• Garbage collection causes jank• Slow reflection, especially on older devices• Managed lifecycle

Page 62: Using and contributing to the next Guice

GWT• Code size really matters• Compiler does full-app optimizations• No reflection.

github.com/tbroyer/sheath

Page 63: Using and contributing to the next Guice

API Designin the GitHub age

Forking makes it easy to stay small & focused

Page 64: Using and contributing to the next Guice

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

Page 65: Using and contributing to the next Guice

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

Page 66: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 67: Using and contributing to the next Guice

PORTABLE CONTROL OF DNS CLOUDS

Page 68: Using and contributing to the next Guice

@Provides @SingletonRoute53 route53(Feign feign, Route53Target target) {

return feign.newInstance(target);}

Dependencies are HTTP Targets

Page 69: Using and contributing to the next Guice

Portable implementations

class Route53ZoneApi implements ZoneApi {

@Inject Route53 route53; ...}

Page 70: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 71: Using and contributing to the next Guice

• Still the best choice for many apps• Broad ecosystem and stable core• May soon be able to mix & match with

Dagger

Guice

Page 72: Using and contributing to the next Guice

• Great for libraries• Extension averse, feature conservative• Friendly forks

Dagger

Page 73: Using and contributing to the next Guice

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