Top Banner
74

Guice Google IO 2009

Apr 20, 2015

Download

Documents

Daniel Iwan
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Guice Google IO 2009
Page 2: Guice Google IO 2009

2

Page 3: Guice Google IO 2009

2

How are we doing?

Share your thoughts on the content and speakers!Complete the session evaluation form on yourcomputer or mobile device at: haveasec.com/io

Next SessionBig Modular Java with Guice

Page 4: Guice Google IO 2009

3

Page 5: Guice Google IO 2009

3

Big Modular Java™ with GuiceJesse WilsonDhanji R. Prasanna

May 28, 2009

Post your questions for this talk on Google Moderator:publicobject.com/google-io

Page 6: Guice Google IO 2009

What youʼll get out of this talkDependency Injection and Guice

> Objects come to you• Instead of ʻnewʼ and factories

> Reusable modules> First-class scopes> Easier tests

• and more confidence> Less boilerplate

4photo courtesy of http://flickr.com/photos/xero79/378837837

Page 7: Guice Google IO 2009

Overview

> Motivation• Ugh, factories arenʼt fun

> Using Guice• @Inject is the new new

> Leveraging Guice• A tour of extensions and advanced features

5

Page 8: Guice Google IO 2009

Exampletweet tweet

6

> Setting the stage> Constructors> Factories> Dependency Injection

• by hand• with Guice

photo courtesy ofhttp://flickr.com/photos/jessicafm/62271212

Page 9: Guice Google IO 2009

Code you might writeA tweets client public void postButtonClicked() {

String text = textField.getText();

if (text.length() > 140) {

Shortener shortener = new TinyUrlShortener();

text = shortener.shorten(text);

}

if (text.length() <= 140) {

Tweeter tweeter = new SmsTweeter();

tweeter.send(text);

textField.clear();

}

}

7

Page 10: Guice Google IO 2009

Calling Dependenciesʼ Constructors Directly

photo courtesy of http://flickr.com/photos/salford_ian/3134250986

Page 11: Guice Google IO 2009

public void postButtonClicked() {

String text = textField.getText();

if (text.length() > 140) {

Shortener shortener = new TinyUrlShortener();

text = shortener.shorten(text);

}

if (text.length() <= 140) {

Tweeter tweeter = new SmsTweeter();

tweeter.send(text);

textField.clear();

}

}

Getting dependencies via their constructors...calling new directly doesnʼt afford testing

9

We post to tinyurl.com and send an SMS for each test! This is neither fast nor reliable.

Page 12: Guice Google IO 2009

Getting Dependencies from Factories

photo courtesy of http://flickr.com/photos/abulic_monkey/130899453

Page 13: Guice Google IO 2009

public void postButtonClicked() {

String text = textField.getText();

if (text.length() > 140) {

Shortener shortener = ShortenerFactory.get();

text = shortener.shorten(text);

}

if (text.length() <= 140) {

Tweeter tweeter = TweeterFactory.get();

tweeter.send(text);

textField.clear();

}

}

Getting dependencies from factories

11

Page 14: Guice Google IO 2009

public class TweeterFactory {

private static Tweeter testValue;

public static Tweeter get() {

if (testValue != null) {

return testValue;

}

return new SmsTweeter();

}

public static void setForTesting(Tweeter tweeter) {

testValue = tweeter;

}

}

Implementing the factoryall of this boilerplate slows you down. Ugh!

12

We still have to write a factory for the URL shortener.

Page 15: Guice Google IO 2009

Factory dependency graphthe static dependency causes monolithic compiles...

13

TweetClient

TweeterFactory

SmsTweeter

depends

depends

Page 16: Guice Google IO 2009

13

TweetClient

TweeterFactory

SmsTweeter ShortenerFactory

TinyUrlShortenerAndroidSms

LoginStoreFactory

LoginStore

CryptoFactory DataFactory

Md5Crypto SqlDataSoapConnection

TagParserFactory

RegexTagParser

SQLite

SoapConnectionFactory

HttpConnectionDomParserFactory

Factory dependency graph...and you end up compiling the whole world

Page 17: Guice Google IO 2009

public void testSendTweet() {

MockTweeter tweeter = new MockTweeter();

TweeterFactory.setForTesting(tweeter);

TweetClient tweetClient = new TweetClient();

tweetClient.getEditor().setText("Hello!");

tweetClient.postButtonClicked();

assertEquals("Hello!", tweeter.getSent());

}

Testing with a factoryitʼs testable

14

Page 18: Guice Google IO 2009

public void testSendTweet() {

MockTweeter tweeter = new MockTweeter();

TweeterFactory.setForTesting(tweeter);

TweetClient tweetClient = new TweetClient();

tweetClient.getEditor().setText("Hello!");

tweetClient.postButtonClicked();

assertEquals("Hello!", tweeter.getSent());

TweeterFactory.setForTesting(null);

}

Testing with a factoryitʼs testable ...but donʼt forget to clean up

15

Page 19: Guice Google IO 2009

public void testSendTweet() {

MockTweeter tweeter = new MockTweeter();

TweeterFactory.setForTesting(tweeter);

try {

TweetClient tweetClient = new TweetClient();

tweetClient.getEditor().setText("Hello!");

tweetClient.postButtonClicked();

assertEquals("Hello!", tweeter.getSent());

} finally {

TweeterFactory.setForTesting(null);

}

}

Testing with a factoryitʼs testable ...but donʼt forget to clean up ...properly!

16

Page 20: Guice Google IO 2009

Dependency Injection (DI) by hand

photo courtesy of http://flickr.com/photos/dan4th/1657850829

Page 21: Guice Google IO 2009

public class TweetClient {

private final Shortener shortener;

private final Tweeter tweeter;

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

public void postButtonClicked() {

...

if (text.length() <= 140) {

tweeter.send(text);

textField.clear();

}

Dependency injection by handobjects come to you

18

Dependency Injection:rather than looking it up, get it passed in.

Page 22: Guice Google IO 2009

public void testSendTweet() {

MockShortener shortener = new MockShortener();

MockTweeter tweeter = new MockTweeter();

TweetClient tweetClient

= new TweetClient(shortener, tweeter);

tweetClient.getEditor().setText("Hello!");

tweetClient.postButtonClicked();

assertEquals("Hello!", tweeter.getSent());

}

Testing with dependency injectionno cleanup required

19

Page 23: Guice Google IO 2009

public class TweetClientFactory {

private static TweetClient testValue;

public static TweetClient get() {

if (testValue != null) {

return testValue;

}

Shortener shortener = ShortenerFactory.get();

Tweeter tweeter = TweeterFactory.get();

return new TweetClient(shortener, tweeter);

}

Where does the dependency go?ugh, you still have to write boilerplate code to build stuff

20

DI motto:Push dependencies from the core to the edges

Page 24: Guice Google IO 2009

Where does the dependency go?your application code sheds its heavyweight dependencies

21

TweetClient

SmsTweeterTinyUrlShortener

depends

creates

TweeterFactoryShortenerFactory

depends

TweetClientFactory

TweeterShortener

depends

Page 25: Guice Google IO 2009

Dependency Injection with Guice

photo courtesy of http://flickr.com/photos/randysonofrobert/347327376

Page 26: Guice Google IO 2009

Dependency injection with Guice

23

TweetClient

SmsTweeterTinyUrlShortener

depends

creates

depends

TweeterShortener

depends

TweeterFactoryShortenerFactory

TweetClientFactory

Page 27: Guice Google IO 2009

Dependency injection with Guice

23

TweetClient

SmsTweeterTinyUrlShortener

depends

creates

depends

TweetModule

Injector

TweeterShortener

depends

Page 28: Guice Google IO 2009

import com.google.inject.AbstractModule;

public class TweetModule extends AbstractModule {

protected void configure() {

bind(Tweeter.class) .to(SmsTweeter.class);

bind(Shortener.class) .to(TinyUrlShortener.class);

}

}

Configuring the injector using modules

24

Page 29: Guice Google IO 2009

import com.google.inject.Inject;

public class TweetClient {

private final Shortener shortener;

private final Tweeter tweeter;

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

Telling Guice to use your constructorannotate a constructor with @Inject

25

Page 30: Guice Google IO 2009

import com.google.inject.Inject;

public class TweetClient {

private final Shortener shortener;

private final Tweeter tweeter;

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

Telling Guice to use your constructorannotate a constructor with @Inject

25

@Inject

Page 31: Guice Google IO 2009

public static void main(String[] args) {

Injector injector = Guice.createInjector(new TweetModule());

TweetClient tweetClient = injector.getInstance(TweetClient.class);

tweetClient.show();

}

Bootstrapping Guice

26

Page 32: Guice Google IO 2009

Using Guice

> Why?> Bindings> Scopes> Injections

27photo courtesy of http://flickr.com/photos/theogeo/2211326536

Page 33: Guice Google IO 2009

Why use Guice?

> Writing boilerplate slows you down> More up front type checking> It makes it easier to write better code

> Plus...• Scopes• AOP• Tight integration with web, data access APIs, etc.

28

Page 34: Guice Google IO 2009

Why use Guice?

> Writing boilerplate slows you down> More up front type checking> It makes it easier to write better code

> Plus...• Scopes• AOP• Tight integration with web, data access APIs, etc.

28

• Google Wave uses it!

Page 35: Guice Google IO 2009

Guice in a nutshell

> Classes have dependencies• these are passed in automatically• identified by annotations

> Modules define how dependencies are resolved

29

Page 36: Guice Google IO 2009

Bindings

photo courtesy of http://flickr.com/photos/uwehermann/3417729678

Page 37: Guice Google IO 2009

Bindingsmap types to their implementations

31

public class TweetModule extends AbstractModule {

protected void configure() {

bind(TweetClient.class);

bind(Tweeter.class) .to(SmsTweeter.class);

bind(String.class).annotatedWith(Username.class) .toInstance("jesse");

}

@Provides Shortener provideShortener() {

return new TinyUrlShortener();

}

}

Page 38: Guice Google IO 2009

Constructor Bindingsto resolve a type, call its constructor

32

public class TweetModule extends AbstractModule {

protected void configure() {

bind(TweetClient.class);

...

}

}

new TweetClient(...)TweetClient

> Requires @Inject on the constructor• Dependencies are passed in as parameters

Page 39: Guice Google IO 2009

Provider methodsto resolve a type, call this method

33

public class TweetModule extends AbstractModule {

protected void configure() {...}

@Provides Shortener provideShortener() {

return new TinyUrlShortener();

}

}

provideShortener(...)Shortener

> Annotate a module method with @Provides• The return type is bound• Dependencies are passed in as parameters

Page 40: Guice Google IO 2009

Linked Bindingsto resolve a type, use another binding

34

public class TweetModule extends AbstractModule {

protected void configure() {

bind(Tweeter.class).to(SmsTweeter.class);

...

}

}

> Requires a binding for the target type• If none exists, one will be created automatically

SmsTweeterTweeter

Page 41: Guice Google IO 2009

Linked Bindingsto resolve a type, use another binding

35

public class TweetModule extends AbstractModule {

protected void configure() {

bind(Tweeter.class).to(SmsTweeter.class);

...

}

}

new SmsTweeter(...)Tweeter

> Requires a binding for the target type• If none exists, one may be created automatically...

SmsTweeter

Page 42: Guice Google IO 2009

Binding Annotationsuniquely identify a binding

36

protected void configure() {

bind(String.class).annotatedWith(Username.class) .toInstance("jesse");

...

}

“jesse”@Username String

@Inject

public SmsTweeter(@Username String username) {

this.username = username;

}

Page 43: Guice Google IO 2009

Defining your own binding annotations

37

@BindingAnnotation

@Retention(RUNTIME)

@Target({FIELD, PARAMETER, METHOD})

public @interface Username {}

> This boilerplate defines a binding annotation> Everything is compile-time checked• IDE autocomplete, import, find usages• Avoids clumsy string matching

Page 44: Guice Google IO 2009

Instance Bindingsalways use the same value

38

protected void configure() {

bind(Integer.class).annotatedWith(Port.class) .toInstance(8080);

...

}

8080@Port Integer

> Best suited for value objects such as a database name, or webserver port

Page 45: Guice Google IO 2009

Using Scopes

photo courtesy of http://flickr.com/photos/houseofsims/3139640931

Page 46: Guice Google IO 2009

Scopesmanage how many

> Scopes manage how instances are reused• because theyʼre stateful• or expensive to construct or lookup• or expensive to maintain

40

Page 47: Guice Google IO 2009

Scopesmanage how many

> Scopes manage how instances are reused• because theyʼre stateful• or expensive to construct or lookup• or expensive to maintain

40

Page 48: Guice Google IO 2009

Common scopes

> Unscoped: one per use• create it, use it, and toss it!• often the best choice

> @Singleton: one per application• for heavyweight resources• and application state

> @RequestScoped: one per web or RPC request> @SessionScoped: one per HTTP session

41

Everything is unscoped by default in Guice.

Page 49: Guice Google IO 2009

Applying scopesthe best way is to annotate a class with its scope

42

public class TweetClient {

...

@Inject

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

Page 50: Guice Google IO 2009

Applying scopesthe best way is to annotate a class with its scope

42

public class TweetClient {

...

@Inject

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

@Singleton

Page 51: Guice Google IO 2009

Applying scopesyou can specify scopes in a module

43

public class TweetModule extends AbstractModule {

protected void configure() {

bind(ConnectionPool.class) .to(ExecutorServicePool.class) .in(Singleton.class);

}

@Provides @Singleton Shortener provideShortener() {

return new TinyUrlShortener();

}

}

Page 52: Guice Google IO 2009

Defining Injections

photo courtesy of http://flickr.com/photos/gaetanlee/631004864

Page 53: Guice Google IO 2009

Constructor injectionto supply dependencies when creating an object

45

public class TweetClient {

private final Shortener shortener;

private final Tweeter tweeter;

@Inject

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

Page 54: Guice Google IO 2009

Constructor injectionto supply dependencies when creating an object

45

public class TweetClient {

private final Shortener shortener;

private final Tweeter tweeter;

@Inject

public TweetClient(Shortener shortener, Tweeter tweeter) {

this.shortener = shortener;

this.tweeter = tweeter;

}

Immutable

Page 55: Guice Google IO 2009

Method injectionsets dependencies into a new or existing instance

46

public class TweetClient {

private Shortener shortener;

private Tweeter tweeter;

@Inject void setShortener(Shortener shortener) {

this.shortener = shortener;

}

@Inject void setTweeter(Tweeter tweeter) {

this.tweeter = tweeter;

}

> Plays nice with inheritance

Page 56: Guice Google IO 2009

Field injectionsets dependencies into a new or existing instance

47

public class TweetClient {

@Inject Shortener shortener;

@Inject Tweeter tweeter;

public TweetClient() {}

> Concise, but difficult to test

Page 57: Guice Google IO 2009

Injecting Providers

photo courtesy of http://flickr.com/photos/toasty/535851893

Page 58: Guice Google IO 2009

The Provider interface

49

public interface Provider<T> {

T get();

}

Page 59: Guice Google IO 2009

Injecting a Provider

50

public class TweetClient {

@Inject Provider<Shortener> shortenerProvider;

@Inject Tweeter tweeter;

public void postButtonClicked() {

String text = textField.getText();

if (text.length() > 140) {

Shortener shortener = shortenerProvider.get();

text = shortener.shorten(text);

}

...

}

Page 60: Guice Google IO 2009

Why inject Providers?

> to load lazily

> to get multiple instances• for example, if you need multiple

DatabaseConnections

> to mix scopes• for example, to access request-scoped objects from

a singleton-scoped object

51

Page 61: Guice Google IO 2009

Leveraging Guice

> Modularity> AJAX via GWT> Servlets and App Engine> AOP> Introspection SPI

52photo courtesy of http://flickr.com/photos/niff/87501285

Page 62: Guice Google IO 2009

ModularitySeparate implementation from interface

53

Page 63: Guice Google IO 2009

ModularitySeparate implementation from interface

53

API

API

APIAPI

API

Page 64: Guice Google IO 2009

ModularitySeparate implementation from interface

53

API

API

APIAPI

API

API

API

APIAPI

API

Page 65: Guice Google IO 2009

ModularitySeparate implementation from interface

53

API

API

APIAPI

API

API

API

APIAPI

API

API

API

API

API

Page 66: Guice Google IO 2009

AJAX via GWTand GIN

> Zero runtime cost: GIN generates JavaScript from modules

> API compatibility with Guice• Great for GWT-RPC• Test without a browser

54

public class MyWidgetClientModule extends AbstractGinModule {

protected void configure() {

bind(MyWidgetMainPanel.class).in(Singleton.class);

bind(MyRemoteService.class) .toProvider(MyRemoteServiceProvider.class);

}

}

Page 67: Guice Google IO 2009

Servlets and App Engine

> Configure your servlets programatically

> Use @RequestScoped and @SessionScoped to manage application state safely and easily

55

public class TweetSearchServletModule extends ServletModule {

protected void configureServlets() {

serve("/search").with(TweetSearchServlet.class);

}

}

Page 68: Guice Google IO 2009

AOPaspect oriented programming

> You can apply method interceptors to injected objects• This is fantastic for cross-cutting concerns like

transactions, security, and performance

56

public class DatabaseTweetStorage implements TweetStorage {

@Transactional

public void saveTweet(String message) {

...

}

}

Page 69: Guice Google IO 2009

Introspection SPIservice provider interface

57

TweetClient

<init>

Tweeter Shortener

SmsTweeter

<init>

@Username

String

TweetModule.java:34

"jesse"

TweetModule.java:38

#provideShortener()

> Module and injector internals are available via a mirror SPI• Inspect, analyze and rewrite

bindings

> Guice uses it internally for...• createInjector()• module overrides• graphing

Page 70: Guice Google IO 2009

Wrapping up...

> Dependency injection leads to testable and reusable code

> Guice makes dependency injection easy• plus it enables scopes• and it integrates neatly with the other APIs you use

> It works on both Java™ SE and Java™ EE• Plus Android, App Engine and GWT (via GIN)

58

Page 71: Guice Google IO 2009

For more information...

> The Guice website documents usage, extensions, and best practices• http://code.google.com/p/google-guice/

> Plus, Dhanji and Robbieʼs books:

59

Page 72: Guice Google IO 2009

For more information...

> The Guice website documents usage, extensions, and best practices• http://code.google.com/p/google-guice/

> Plus, Dhanji and Robbieʼs books:

59

depinj40manning.com/prasanna

Page 73: Guice Google IO 2009

Q & APost your questions for this talk on Google Moderator:publicobject.com/google-io

Page 74: Guice Google IO 2009