Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice...

28
Dependency Injection Robert Walter MSI 3 EMFW WS 08/09 13.11.2008

Transcript of Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice...

Page 1: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

Dependency

Injection

Robert WalterMSI 3EMFW WS 08/09

13.11.2008

Page 2: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 2

/ 46

Overview

• Outline• References• Necessity• Simple Example Design• Summary

Page 3: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 3

/ 46

Outline

• Not focussing on– Different frameworks

(Spring vs. PicoContainer vs. Avalon vs. Guice vs. …)– DI vs. Service Locator Pattern

• Instead– Simple example design– Different approaches

• Factory• Dependency Injection by Hand• Dependency Injection with Google Guice

Page 4: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 4

/ 46

Overview

• Outline• References• Necessity• Simple Example Design• Summary

Page 5: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 5

/ 46

ReferencesMartin Fowler. Inversion of Control Containers and the DependencyInjection pattern. 2004. URL: http://martinfowler.com/articles/injection.html

Bob Lee. Java on Guice: Dependency Injection, the Java Way. 2007. URL: http://video.google.com/videosearch?q=Guice&emb=0#URL: http://crazybob.org/

Framework‐Homepages: PicoContainer, Spring, Google Guice, …

Wikipedia

Page 6: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 6

/ 46

Overview

• Outline• References• Necessity• Simple Example Design• Summary

Page 7: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 7

/ 46

Necessity

• Dependencies between objects lead to several problems regarding– Reusability– Flexibility– Scalability– Maintainability– (Unit)‐Testing

• Use of interfaces alone is not enough (as some design patterns are not)

Page 8: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 8

/ 46

Misusing an Interface ( Fowler)

<<interface>>MovieFinder

ColonDelimitedMF

MovieLister

<<creates>>class MovieLister {

private MovieFinder finder;public MovieLister() {

finder = new ColonDelimitedMF("movies1.txt");}

public Movie[] moviesDirectedBy(String arg) {List allMovies = finder.findAll();for (Iterator it = allMovies.iterator(); it.hasNext();) {

Movie movie = (Movie) it.next();if (!movie.getDirector().equals(arg))

it.remove();}return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);

}}

Page 9: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 9

/ 46

Using an Interface right

<<interface>>MovieFinder

ColonDelimitedMF

MovieLister

class MovieLister {private MovieFinder finder;public MovieLister(MovieFinder inFinder) {

finder = inFinder;}

public Movie[] moviesDirectedBy(String arg) {List allMovies = finder.findAll();for (Iterator it = allMovies.iterator(); it.hasNext();) {

Movie movie = (Movie) it.next();if (!movie.getDirector().equals(arg))

it.remove();}return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);

}}

In a complex system, a configuration needs to know whichLister gets which implementation injected.

Page 10: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 10

/ 46

Overview

• Outline• References• Necessity• Simple Example Design• Summary

Page 11: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 11

/ 46

High Level Design ( Bob Lee)

ServiceClientClientTest

ServiceImpl• three approaches

– factory– dependency injection by Hand– dependency injection with Google Guice

• what differs?– how does client get an instance of service?

Page 12: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 12

/ 46

public interface Service {void go();

}

public class ServiceImpl implements Service {void go(){

// expensive stuff}

}

High Level Design ( Bob Lee)

Service

ServiceImpl

ClientClientTest

• what is constant?

Page 13: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 13

/ 46

High Level Design ( Bob Lee)

ServiceClientClientTest

MockServicepublic class MockService implements Service {private boolean gone = false;public void go(){

gone = true;}public boolean isGone(){

return gone;}

}

• what is constant?

Page 14: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 14

/ 46

Factory Approachpublic class Client {

public void go() {Service service = ServiceFactory.getInstance(); service.go();

}}

public class ServiceFactory {private ServiceFactory() {}

private static Service instance = new ServiceImpl();// decoupling clients from implementationpublic static Service getInstance() {return instance;

}// for testing purposepublic static void setInstance(Service service) {instance = service;

}}

Page 15: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 15

/ 46

Factory Approach – Unit Test

public void testClient() {

Service previous = ServiceFactory.getInstance();

try {final MockService mock = new MockService();ServiceFactory.setInstance(mock);Client client = new Client();client.go();assertTrue(mock.isGone());

}finally{// why is restoring necessary?ServiceFactory.setInstance(previous);

}}

– to avoid breaking other tests– tests in different threads could still break

Page 16: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 16

/ 46

Factory Observations

• Unit test has to pass the mock to the factory and then clean up afterwards.

• You have to look at the implementation of Client to know it depends on Service.

• Reusing Client in a different context will be difficult.

• Same factory code for every dependency• Client has a compile time dependency on 

ServiceImpl

Page 17: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 17

/ 46

Dependency Injection by Hand

public class Client {private final Service service;

public Client(Service service) {// Service service = ServiceFactory.getInstance();this.service = service;

}

public void go() {service.go();

}}

„Don`t call me. I`ll call you.“DI is a specific form of Inversion of Control

Page 18: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 18

/ 46

Factory – Unit Test (Again)

public void testClient() {

Service previous = ServiceFactory.getInstance();

try {final MockService mock = new MockService();ServiceFactory.setInstance(mock);Client client = new Client();client.go();assertTrue(mock.isGone());

}finally{ServiceFactory.setInstance(previous);

}}

Page 19: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 19

/ 46

public void testClient() {MockService mock = new MockService();Client client = new Client(mock);client.go();assertTrue(mock.isGone());

}

Dependency Injection – Unit Test

Page 20: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 20

/ 46

DI Observations

• Business objects are easy to test• Clients can`t be created without a Service• Client can be used with different services, even in 

the same application• No compile time dependency between Client and 

ServiceImpl– Dependency is moved to the application layer– Testing small compilation units possible

• How is a client created / configured?– Factory?

Page 21: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 21

/ 46

DI Client creation

public class ClientFactory {

private ClientFactory() {}

public static Client getInstance() {Service service = ServiceFactory.getInstance();return new Client(service);

}}

Even more factories needed on application layer!More general: DI configuration can be tough and annoying!

Page 22: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 22

/ 46

Dependency Injection with Guice

public class MyModule extends AbstractModule {

protected void configure() {bind(Service.class) // bind Service Interface.to(ServiceImpl.class) // to ServiceImpl.in(Scopes.SINGLETON); // and make it a Singleton

} }

Replacing factories by modules:

Page 23: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 23

/ 46

Dependency Injection with Guice

public class Client {private final Service service;

@Inject // tells Guice where to inject thingspublic Client(Service service) {this.service = service;

}

public void go() {service.go();

}}

Guice needs to know where it should inject something(instead of ourselfs implementing factories)

Page 24: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 24

/ 46

DI with Guice ‐ Testing

public void testClient() {MockService mock = new MockService();Client client = new Client(mock);client.go();assertTrue(mock.isGone());

}

Stays exactly the same!

Page 25: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 25

/ 46

Using Guice ‐ Bootstrapping

public class MyApplication {public static void main(String[] args) {Injector injector = Guice.createInjector(new MyModule());Client client = injector.getInstance(Client.class);client.go();

}}

public class MyModule extends AbstractModule {

protected void configure() {bind(Service.class) // bind Service Interface.to(ServiceImpl.class) // to ServiceImpl.in(Scopes.SINGLETON); // and make it a Singleton

} }

Injector only needs to be applied once. All other dependenciesget injected by Guice.

Page 26: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 26

/ 46

Adding further dependencies

public class ServiceImpl implements Service {@Inject // the new „new“Emailer emailer;

void go(){// expensive stuff...// send confirmationemailer.send(...);

}}

public class Emailer { // concrete class...send(...) { ... }

}

ServiceImpl is „in the club“ (thanks to the injector)

Page 27: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 27

/ 46

Overview

• Outline• References• Necessity• Simple Example Design• Summary

Page 28: Dependency Injection• Dependency Injection by Hand • Dependency Injection with Google Guice 13.11.2008 Robert Walter ‐MSI 3 4 / 46 Overview •Outline • References • Necessity

13.11.2008Robert Walter ‐MSI 3 28

/ 46

Summary

• DI is a simple yet powerful mechanism• Identification of where to use it is hard• Different frameworks support developers with

– „lightweight components“ / injectors– more fancy stuff

• Benefits– Decoupling of components– Testing / Reusability / Flexibility / Maintainability

• Downsides– Configuration needed (could get complex)