41
Practical introduction to Dependency Injection Author: Tamas Rev email: [email protected] Blog: tamasrev.wordpress.com Twitter: @tamasrev

Practical introduction to dependency injection

Embed Size (px)

Citation preview

Page 1: Practical introduction to dependency injection

Practical introduction to Dependency Injection

Author: Tamas Revemail: [email protected]: tamasrev.wordpress.comTwitter: @tamasrev

Page 2: Practical introduction to dependency injection

What is Dependency Injection?

• It’s the callers responsibility to specify the details (which message sender).

• It’s the responsibility of the service to provide generic solutions (what message do we send)

• Hollywood principle (don’t call the framework)

Page 3: Practical introduction to dependency injection

Benefits of DI

• Modularity• Flexible code• Testability• Decoupling metadata from actual code• …– Similar to those of TDD

Page 4: Practical introduction to dependency injection

Problems with DI

• Lots of XML– Difficult, but you cannot mix metadata with code

• Bloated constructor– Ugly but provides compile-time checks

• Depending on a framework– Unless you apply the Hollywood principle

Page 5: Practical introduction to dependency injection

DI (IoC) frameworks

• Spring• JAVA EE CDI• Guice• Tapestry-DI• Treasure map• PicoContainer• Dagger (for Android)• …

Page 6: Practical introduction to dependency injection

Focus

Page 7: Practical introduction to dependency injection

Focus

• DI features of Dependency Injection Frameworks

• Spring, Guice, Tapestry-DI

Page 8: Practical introduction to dependency injection

Not in focus

• Receiving a little focus– Aspects / Decorators / Interceptors

• Definitely not in focus:– Frameworks not mentioned above

Page 9: Practical introduction to dependency injection

Sandbox

• FizzBuzz kata

Page 10: Practical introduction to dependency injection

FizzBuzz Kata

• Print the numbers 1..100 to the STDOUT. Except:– For numbers divisible by 3 you should print “Fizz”– For numbers divisible by 5 you should print “Buzz”– For numbers divisible by both 3 and 5 you should

print “FizzBuzz”• http://codingdojo.org/cgi-bin/index.pl?

KataFizzBuzz

Page 11: Practical introduction to dependency injection

FizzBuzz Cowboypublic class FizzBuzzCowBoy { public static void main(final String... args) { for (int i = 1; i <= 100; i++) { if (i % 15 == 0) { System.out.println("FizzBuzz"); } else if (i % 5 == 0) { System.out.println("Buzz"); } else if (i % 3 == 0) { System.out.println("Fizz"); } else { System.out.println(i); } } }}

Page 12: Practical introduction to dependency injection

Enterprise FizzBuzz

• Some requirements can be:– Maybe you need tests– Maybe you need to send the lines in email– Maybe you need to group the lines– Maybe you need to change the logic– …

• Dependency Injection to the rescue!

Page 13: Practical introduction to dependency injection

No framework – abstract logicpublic class FizzBuzzManualInjection { private final FizzBuzzNumberProvider numberProvider; private final FizzBuzzTextProvider textProvider; private final FizzBuzzPrinter printer; public FizzBuzzManualInjection(final FizzBuzzNumberProvider numberProvider, final FizzBuzzTextProvider textProvider, final FizzBuzzPrinter printer) { this.numberProvider = numberProvider; this.textProvider = textProvider; this.printer = printer; } public void doFizzBuzz() { numberProvider.getFizzBuzzNumbers().forEach(num -> { final String msg = textProvider.getFizzBuzzText(num); printer.printFizzBuzz(msg); }); }}

Page 14: Practical introduction to dependency injection

No framework – mainpublic class Main { public static void main(final String[] args) { final FizzBuzzNumberProvider numberProvider = new FizzBuzzNumberProvider(); final FizzBuzzTextProvider textProvider = new FizzBuzzTextProvider(); final FizzBuzzPrinter printer = new FizzBuzzPrinter(); final FizzBuzzManualInjection fizzBuzz = new FizzBuzzManualInjection(numberProvider, textProvider, printer); fizzBuzz.doFizzBuzz(); }}

Page 16: Practical introduction to dependency injection

Bootstrapping the framework

• I.e. writing the main

Page 17: Practical introduction to dependency injection

Spring framework

• The de facto IoC framework for java• Since 2002• Feature-rich: dependency injection, aspects,

templates and lots of other stuff

Page 18: Practical introduction to dependency injection

Spring - mainpublic class Main {

public static void main(final String[] args) { try (final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("fizzbuzz.spring.xml")) { final FizzBuzzService fizzBuzzService = context.getBean(FizzBuzzService.class); fizzBuzzService.doFizzBuzz(); } }

}

Page 19: Practical introduction to dependency injection

Spring java config - mainpublic class Main {

public static void main(final String[] args) { try (final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FizzBuzzConfig.class)) { final FizzBuzzService fizzBuzz = context.getBean(FizzBuzzService.class); fizzBuzz.doFizzBuzz(); } }

}

This is the only difference

Page 20: Practical introduction to dependency injection

Google Guice

• A Dependency Injection framework by Google• Originally developed for Google Wave• Lightweight, annotation based• Since 2008

Page 21: Practical introduction to dependency injection

Guicepublic class Main {

public static void main(final String[] args) { // This is for the constructor with concrete classes //final Injector injector = Guice.createInjector();

final Injector injector = Guice.createInjector(new FizzBuzzModule());

final FizzBuzzGuiceService fizzBuzz = injector.getInstance(FizzBuzzGuiceService.class);

fizzBuzz.doFizzBuzz();

}

}

Page 22: Practical introduction to dependency injection

Tapestry-DI

• An IoC framework behind the Tapestry framework

• It makes web development easy: you can inject components and generic services too

Page 23: Practical introduction to dependency injection

Tapestry-DI - mainpublic class Main {

public static void main(final String[] args) { // code inspired by http://wiki.apache.org/tapestry/Tapestry5HowToIocOnly final RegistryBuilder builder = new RegistryBuilder(); builder.add(FizzBuzzModule.class);

final Registry registry = builder.build(); registry.performRegistryStartup();

final FizzBuzzTapestryService fizzBuzz = registry.getService(FizzBuzzTapestryService.class); fizzBuzz.doFizzBuzz(); }

}

Page 24: Practical introduction to dependency injection

DI configuration

• XML• Annotations• java statements

Page 25: Practical introduction to dependency injection

Spring – xml configuration<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" ... >

<bean id="fizzBuzz" class="com.trev.fizzbuzz.inject.spring.FizzBuzzService" > <property name="numberProvider" ref="fizzbuzz.numberProvider" /> <property name="textProvider" ref="fizzbuzz.textProvider" /> <property name="printer" ref="fizzbuzz.printer" /> </bean>

</beans>

Page 26: Practical introduction to dependency injection

Spring – xml configuration<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" ... >

<bean id="fizzBuzz" class="com.trev.fizzbuzz.inject.spring.FizzBuzzService" > <property name="numberProvider" ref="fizzbuzz.numberProvider" /> <property name="textProvider" ref="fizzbuzz.textProvider" /> <property name="printer" ref="fizzbuzz.printer" /> </bean>

</beans>

This is a bean definition

Bean ID

Bean configuration

Page 27: Practical introduction to dependency injection

Spring javaconfig// They call them beans – that live in a configuration@Configurationpublic class FizzBuzzConfig { // where did we see this before?

@Bean // almost <bean> public FizzBuzzPrinter fizzBuzzPrinter() { return new DefaultFizzBuzzPrinter(); }

// ...}

Page 28: Practical introduction to dependency injection

Spring javaconfig// They call them beans – that live in a configuration@Configurationpublic class FizzBuzzConfig { // where did we see this before?

@Bean // almost <bean> public FizzBuzzPrinter fizzBuzzPrinter() { return new DefaultFizzBuzzPrinter(); }

// ...}

So we know it defines beans

This is a bean definition

The abstract type of the bean

Bean ID

Bean configurationand other initialization

Page 29: Practical introduction to dependency injection

Guice config// They call them bindings – that reside in a modulepublic class FizzBuzzModule extends AbstractModule {

@Override protected void configure() { bind(FizzBuzzNumberProvider.class).to(DefaultNumberProvider.class); bind(FizzBuzzPrinter.class).to(DefaultFizzBuzzPrinter.class); bind(FizzBuzzTextProvider.class).to(DefaultTextProvider.class); }

}

Page 30: Practical introduction to dependency injection

Guice config// They call them bindings – that reside in a modulepublic class FizzBuzzModule extends AbstractModule {

@Override protected void configure() { bind(FizzBuzzNumberProvider.class).to(DefaultNumberProvider.class); bind(FizzBuzzPrinter.class).to(DefaultFizzBuzzPrinter.class); bind(FizzBuzzTextProvider.class).to(DefaultTextProvider.class); }

}

So we know it defines services

The abstract type of the serviceThis is the service id too

Service configuration across the bindingsConcrete type of the service.I.e. what do we inject.

Page 31: Practical introduction to dependency injection

Tapestry-DI config// They call them bindings – that reside in a modulepublic class FizzBuzzModule {

public static void bind(final ServiceBinder binder) { binder.bind(FizzBuzzNumberProvider.class, DefaultNumberProvider.class); binder.bind(FizzBuzzPrinter.class, DefaultFizzBuzzPrinter.class); binder.bind(FizzBuzzTextProvider.class, DefaultTextProvider.class); binder.bind(FizzBuzzTapestryService.class); // concrete service class }

}

Page 32: Practical introduction to dependency injection

Tapestry-DI config// They call them bindings – that reside in a modulepublic class FizzBuzzModule {

public static void bind(final ServiceBinder binder) { binder.bind(FizzBuzzNumberProvider.class, DefaultNumberProvider.class); binder.bind(FizzBuzzPrinter.class, DefaultFizzBuzzPrinter.class); binder.bind(FizzBuzzTextProvider.class, DefaultTextProvider.class); binder.bind(FizzBuzzTapestryService.class); // concrete service class }

}

Must place to the right package,so we know it defines services

The abstract type of the serviceThis is the service id too

Service configuration across the bindingsConcrete type of the service.I.e. what do we inject.

Page 33: Practical introduction to dependency injection

Magic

Page 34: Practical introduction to dependency injection

Aspects

• Advices• Interceptors• Typically used for– Transaction– Performance measurement– Logging

• Problem: too much magic

Page 35: Practical introduction to dependency injection

What magic?

• Proxy– Proxy Pattern (GoF)– java.lang.reflect.Proxy

• Difficult to find the aspect implementation• Stack traces from hell

Page 36: Practical introduction to dependency injection

Stack traces from hell• http://

www.nurkiewicz.com/2012/03/filtering-irrelevant-stack-trace-lines.html

…at sun.reflect.NativeMethodAccessorImpl.invoke0()at sun.reflect.NativeMethodAccessorImpl.invoke()at sun.reflect.DelegatingMethodAccessorImpl.invoke()at java.lang.reflect.Method.invoke()at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs()at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod()…

Page 37: Practical introduction to dependency injection

Tapestry – @CommitAfter• In HibernateModule:@Contribute(ComponentClassTransformWorker2.class)@Primarypublic static void provideCommitAfterAnnotationSupport(OrderedConfiguration configuration) { // If logging is enabled, we want logging to be the first advice, wrapping around the commit advice. configuration.addInstance("CommitAfter", CommitAfterWorker.class, "after:Log");}• Need to do a few more steps to

Page 38: Practical introduction to dependency injection

Tapestry - CommitAfterWorkerpublic class CommitAfterMethodAdvice implements MethodAdvice { @Override public void advise(final MethodInvocation invocation) { //... skipped some stuff for brevity if (transaction != null && !transaction.isActive()) { transaction.begin(); } try { invocation.proceed(); // going on with the method being annotated } catch (final RuntimeException e) { if (transaction != null && transaction.isActive()) { rollbackTransaction(transaction); } throw e; } if (transaction != null && transaction.isActive()) { transaction.commit(); } //... skipped some stuff for brevity }}

Page 39: Practical introduction to dependency injection

Spring - @Transactional

• TransactionalInterceptor• Won’t fit into this slide• Can deal with distributed transactions too

Page 40: Practical introduction to dependency injection

Wrapping up

• All the frameworks are very similar, but they call the same thing differently.

• Bean / Service are equivalent• Module / Config are equivalent• Aspect / Interceptors / Decorators / Method

advices are equivalent

Page 41: Practical introduction to dependency injection

Questions