Dagger 2. The Right Way to Dependency Injections

35
Dagger 2. Right way to do Dependency Injections by Anton Minashkin

Transcript of Dagger 2. The Right Way to Dependency Injections

Page 1: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Right way to do Dependency Injections

by Anton Minashkin

Page 2: Dagger 2. The Right Way to Dependency Injections

Usual JAVA codepublic class Payroll { ...

public long getWithholding(long payInDollars) { ... return withholding; }

public long getAfterTaxPay(Employee employee) { long basePay = EmployeeDatabase.getInstance() .getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 3: Dagger 2. The Right Way to Dependency Injections

Usual JAVA codepublic class Payroll { ...

public long getWithholding(long payInDollars) { ... return withholding; }

public long getAfterTaxPay(Employee employee) { long basePay = EmployeeDatabase.getInstance() .getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 4: Dagger 2. The Right Way to Dependency Injections

Usual JAVA codepublic class Payroll { ...

public long getWithholding(long payInDollars) { ... return withholding; }

public long getAfterTaxPay(Employee employee) { long basePay = new EmployeeDatabase() .getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 5: Dagger 2. The Right Way to Dependency Injections

What is DI?

In software engineering, dependency

injection is a software design pattern that

implements inversion of control for software

libraries.

Page 6: Dagger 2. The Right Way to Dependency Injections

What is DI?

Page 7: Dagger 2. The Right Way to Dependency Injections

Say “Hi!” to DIpublic class Payroll { ... EmployeeDatabase mEmployeeDatabase; public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = mEmployeeDatabase.getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 8: Dagger 2. The Right Way to Dependency Injections

Say “Hi!” to DIpublic class Payroll { ... EmployeeDatabase mEmployeeDatabase; public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; } public long getWithholding(long payInDollars) { ... return withholding; } public long getAfterTaxPay(Employee employee) { long basePay = mEmployeeDatabase.getBasePay(employee); long withholding = getWithholding(basePay);

return basePay - withholding; }}

Page 9: Dagger 2. The Right Way to Dependency Injections

...but!

Was:new Payroll().getAfterTaxPay(employee);

Now:new Payroll(EmployeeDatabase.getInstance()) .getAfterTaxPay(employee);

Page 10: Dagger 2. The Right Way to Dependency Injections

...but!

Was:new Payroll().getAfterTaxPay(employee);

Now:new Payroll(EmployeeDatabase.getInstance()) .getAfterTaxPay(employee);

Page 11: Dagger 2. The Right Way to Dependency Injections

Java! To the rescue!

JSR-330

Page 12: Dagger 2. The Right Way to Dependency Injections

JSR-330public class Payroll { … @Inject public Payroll(EmployeeDatabase employeeDatabase) { mEmployeeDatabase = employeeDatabase; }…}

ORpublic class Payroll { … @Inject EmployeeDatabase mEmployeeDatabase; ...}

Page 13: Dagger 2. The Right Way to Dependency Injections

DI frameworks

● Google Guice● Spring DI● Java EE6 CDI● Dagger● etc.

Page 14: Dagger 2. The Right Way to Dependency Injections

DI frameworks

● Google Guice● Spring DI● Java EE6 CDI● Dagger● etc.

Page 15: Dagger 2. The Right Way to Dependency Injections

Dagger 2. History

Developed by SquareAdopted by Google (Dagger 2)

Page 16: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Main features

● Android friendly● JSR-330● Compile-time DI validation● Full stack code generation● User mimic code● Easy to debug & understand

Page 17: Dagger 2. The Right Way to Dependency Injections

Dagger 2. API

class Thermosiphon implements Pump {

private final Heater heater;

@Inject

Thermosiphon(Heater heater) {

this.heater = heater;

}

...

}

Page 18: Dagger 2. The Right Way to Dependency Injections

Dagger 2. API

class CoffeeMaker {

@Inject Heater heater;

@Inject Pump pump;

...

}

Page 19: Dagger 2. The Right Way to Dependency Injections

Dagger 2. API

@Module

class DripCoffeeModule {

@Provides Heater provideHeater() {

return new ElectricHeater();

}

@Provides Pump providePump(Thermosiphon pump) {

return pump;

}

}

Page 20: Dagger 2. The Right Way to Dependency Injections

Dagger 2. API

@Component(modules = DripCoffeeModule.class)

interface CoffeeShop {

CoffeeMaker maker();

}

Page 21: Dagger 2. The Right Way to Dependency Injections

Dagger 2. API

CoffeeShop coffeeShop = DaggerCoffeeShop.builder()

.dripCoffeeModule(new DripCoffeeModule())

.build();

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

Page 22: Dagger 2. The Right Way to Dependency Injections

Dagger 2. API

public class CoffeeApp {

public static void main(String[] args) {

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

coffeeShop.maker().brew();

}

}

Page 23: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Scope

@Provides @Singleton Heater provideHeater() {

return new ElectricHeater();

}

Page 24: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Lazy

class GridingCoffeeMaker {

@Inject Lazy<Grinder> lazyGrinder;

public void brew() {

while (needsGrinding()) {

// Grinder created once on first call to .get() and cached.

lazyGrinder.get().grind();

}

}

}

Page 25: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Provider Injection

class BigCoffeeMaker {

@Inject Provider<Filter> filterProvider;

public void brew(int numberOfPots) {

...

for (int p = 0; p < numberOfPots; p++) {

maker.addFilter(filterProvider.get()); //new filter every time.

maker.addCoffee(...);

maker.percolate();

...

}

}

}

Page 26: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Qualifiers

@Qualifier

@Documented

@Retention(RUNTIME)

public @interface Named {

String value() default "";

}

Page 27: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Qualifiers

class ExpensiveCoffeeMaker {

@Inject @Named("water") Heater waterHeater;

@Inject @Named("hot plate") Heater hotPlateHeater;

...

}

Page 28: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Qualifiers

@Provides @Named("hot plate") Heater provideHotPlateHeater() {

return new ElectricHeater(70);

}

@Provides @Named("water") Heater provideWaterHeater() {

return new ElectricHeater(93);

}

Page 29: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Compile-time validation

@Module

class DripCoffeeModule {

@Provides Heater provideHeater(Executor executor) {

return new CpuHeater(executor);

}

}…

[ERROR] COMPILATION ERROR :

[ERROR] error: java.util.concurrent.Executor cannot be provided without an @Provides-

annotated method.

Page 30: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Generated code @Override public DataManager get() { DataManager provided = module.provideDataManager(authApiProvider.get(), articleApiProvider.get(), commentsApiProvider.get()); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; }

public static Factory<DataManager> create(DataManagerModule module, Provider<AuthApi> authApiProvider, Provider<ArticleApi> articleApiProvider, Provider<CommentApi> commentApiProvider) { return new DataManagerModule_ProvideDataManagerFactory(module, authApiProvider, articleApiProvider, commentApiProvider); }

Page 31: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Debugging

Here should be example of Guice stacktrace:VERY-VERY-BAD-STACKTRACE

And here is Dagger stacktrace:Mmmm… What a lovely stacktrace!

Page 32: Dagger 2. The Right Way to Dependency Injections

Dagger 2. What should I inject?

● Anything that has constructor parameters● Anything that is out of local scope● Infrastructure● Anything that is shared between >1 objects● Diferent obj-graphs for diferent flavors

Page 33: Dagger 2. The Right Way to Dependency Injections

Dagger 2. Where should I inject?public class MyApp extends Application {@Overridepublic void onCreate() {registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {... @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { inject(activity); }...});}

Page 34: Dagger 2. The Right Way to Dependency Injections

Dagger 2

Questions?

Page 35: Dagger 2. The Right Way to Dependency Injections

RTFM!

http://google.github.io/dagger/https://youtu.be/oK_XtfXPkqw

[email protected]