Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

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

Transcript of Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Page 1: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Dagger 2. Right way to do Dependency Injections

by Anton Minashkin

Page 2: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do 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. Right way to do 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. Right way to do 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. Right way to do Dependency Injections"

What is DI?

Page 7: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do 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. Right way to do Dependency Injections"

...but!

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

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

Page 10: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

...but!

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

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

Page 11: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Java! To the rescue!

JSR-330

Page 12: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

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

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

Page 13: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

DI frameworks

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

Page 14: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

DI frameworks

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

Page 15: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Dagger 2. History

Developed by SquareAdopted by Google (Dagger 2)

Page 16: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do Dependency Injections"

Dagger 2. API

class Thermosiphon implements Pump {

private final Heater heater;

@Inject

Thermosiphon(Heater heater) {

this.heater = heater;

}

...

}

Page 18: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Dagger 2. API

class CoffeeMaker {

@Inject Heater heater;

@Inject Pump pump;

...

}

Page 19: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do Dependency Injections"

Dagger 2. API

@Component(modules = DripCoffeeModule.class)

interface CoffeeShop {

CoffeeMaker maker();

}

Page 21: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Dagger 2. API

CoffeeShop coffeeShop = DaggerCoffeeShop.builder()

.dripCoffeeModule(new DripCoffeeModule())

.build();

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

Page 22: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do Dependency Injections"

Dagger 2. Scope

@Provides @Singleton Heater provideHeater() {

return new ElectricHeater();

}

Page 24: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do 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. Right way to do Dependency Injections"

Dagger 2. Qualifiers

@Qualifier

@Documented

@Retention(RUNTIME)

public @interface Named {

String value() default "";

}

Page 27: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

Dagger 2. Qualifiers

class ExpensiveCoffeeMaker {

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

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

...

}

Page 28: Антон Минашкин "Dagger 2. Right way to do 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. Right way to do 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. Right way to do 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. Right way to do 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. Right way to do 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. Right way to do 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. Right way to do Dependency Injections"

Dagger 2

Questions?

Page 35: Антон Минашкин "Dagger 2. Right way to do Dependency Injections"

RTFM!

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

[email protected]