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

Dagger 2. The Right Way to Dependency Injections

Embed Size (px)

Citation preview

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]