Transcript
Page 1: Jhug nov11-google guice

Google Guice

JHUG November 2011Anastasopoulos [email protected]

Page 2: Jhug nov11-google guice

What is Google Guice

@SimplyA library that helps manipulate the object graph and write maintainable code

@BuzzwordCompliantA dependency injector for modular java

@LikeThe spring application context or J2EE CDI

Page 3: Jhug nov11-google guice

The Object Graph

A java program creates, wires and uses objects.// grep <pattern>public static void main(String[] args) throws Exception { BufferedReader bin = new BufferedReader(newInputStreamReader(System.in)); PrintWriter bout = new PrintWriter(new BufferedOutputStream(System.out));

Pattern p = Pattern.compile(args[0]); String line = null; while ((line = bin.readLine()) != null) { Matcher m = p.matcher(line); if (m.find()) bout.println(line); }}

Page 4: Jhug nov11-google guice

The Object Graph

Objects need the assistance of other objects to do their job. A program must ensure that an object is given references to the other objects it needs (its dependencies) before that object has to do anything. This leads to the object graph.

Service

Validator

Enhancer

AdapterLogger

Storage

Page 5: Jhug nov11-google guice

The Object Graph

Out of the box the language supports only a single object - new, equals(), hash(), =, finalize()

There is no support for the object graph with callbacks like - onCreation(), onReference(), onUse()

The work to handle the object graph is left on the programmer.

To make things more difficult, not all objects are the same. Some are expensive(DBConnection), some are for a lifetime(ApplicationMonitor), some can be reused (HttpConnection), some are immutable(Long), some are in flux(ConcurrentHashMap), some are scoped(HttpRequest), some are OS dependent(Socket) and so on...

This leads to ...

Page 6: Jhug nov11-google guice

Static References

public void processAndStore(InputData data) { DataValidator dv = new NASDataValidator(); if (dv.areDataValid(data)) { AmazonS3Storage ds = new AmazonS3Storage(S3URL); ds.store(data); } else { FileStorage ds = new FileStorage("./data.txt", data); LogDataTransformer dt = Context.getDataTransformer(); logger.info("Invalid NAS Data: " + dt.transform(data)); }}

● tight coupling on implementation● code not polymorphic● cannot be reused in another context, all or nothing testing● viral, easy to spread though code base● dependencies are implicit, hidden in the code● hard to maintain and refactor

Page 7: Jhug nov11-google guice

Design Patterns to the rescue?

● Abstract Factory, Factory Method● Object Pools, Object Caches, Lazy Loading● Builder● Prototype● Service Locator● Singleton

Most design patterns are informal: described in prose; refer to by name, but must be implemented from scratch for each use(Peter Norvig)

Remember static references are viral while design patterns are just convention (Hint: maintainability)

Page 8: Jhug nov11-google guice

Design Patterns to the rescue? Not me

● Factory○ how to get it? global, use locator, use metafactory etc○ code now depends on implementation of factory○ boilerplate code. We will need many factories○ reuse in a different context is difficult (testing)○ dependencies are still hidden in the implementation

● Service Locator○ how to configure it?○ how to ensure availability?○ hard to tell what services an object will need (no tools)○ looses some type safety

Page 9: Jhug nov11-google guice

Dependency Injection (DI)

A style of programming that promises● less boilerplate code● easy reuse and maintainance● easy unit testing

The leap of faith is that an object doesn't do anything to resolve its dependencies but assumes they will be resolved by someone else and passed to the object by the time it will have to do some work. The resolution is done either by user code or by a framework (Guice, Spring, CDI etc)

The main benefits of DI are● separation between behavior and dependency resolution● dependencies are now exposed in the API

Page 10: Jhug nov11-google guice

DI example

Assuming that we have

class Client { private Service service;

public Client(Service service) { this.service = service;} public int doWork(int volume) { // uses service }}

A user of Client Client cli = new Client(new ProductionService()); cli.doWork();

A unit test of Client Client cli = new Client(new MockService()); assertEquals(cli.doWork(10), 50);

Page 11: Jhug nov11-google guice

DI with Spring

Write an XML configuration file

<beans> <bean id="service" class="com.services.ProductionService"/> <bean id="client" class="com.clients.DefaultClient"> <constructor-arg><ref bean="service"/></constructor-arg> </bean></beans>

Use it to create the injector, then get objects

public static void main(String[] args) { ApplicationContext ctxt = new ClassPathXmlApplicationContext("applicationContext.xml");

Client cli = ctxt.getBean("client"); client.work(10);}

Page 12: Jhug nov11-google guice

Google Guice

● Created and used by Google● Releases 1.0 Mar 2007 - 2.0 May 2009 - 3.0 Mar 2011● At time of first release Spring did not meet their needs

○ no support for Java 5 features, generics and annotations○ verbose XML configuration and inadequate tool support○ XML is code○ Spring vision was a comprehensive alternative to J2EE

● Guice went back to the basics○ focus on dependency injection○ support type safety, generics, annotations○ ease of use, good error messages○ maximum power-to-weight ratio of API

Page 13: Jhug nov11-google guice

Why Guice? It is a matter of taste

Spring is an excellent piece of software but like everything in the java world it has made configuration first priority. You can configure it in many ways to do many things implicit or explicit● It does not enforce or suggest a one true way to use it.

J2EE is the standard with all the pros and cons.● Why do we need to standardize everything?

Guice is just a tool that can help you build applications. It does not try to recreate the world and it does not try to dominate your application.● Designed to support and favor a particular good code style

Page 14: Jhug nov11-google guice

Applied Guice: the application

interface Greeter { void greet();}

public class WelcomeGreeter implements Greeter { public void greet() { System.out.println("Welcome\n"); }

public class Main { private Greeter gt;

void setGreeter(Greeter gt) { this.gt = gt; }

public void doIt() { gt.greet(); }}

Page 15: Jhug nov11-google guice

Applied Guice: the application Guicified

interface Greeter { void greet();}

public class WelcomeGreeter implements Greeter { public void greet() { System.out.println("Welcome\n"); }

public class Main { private Greeter gt;

@Inject void setGreeter(Greeter gt) { this.gt = gt; }

public void doIt() { gt.greet(); }}

Page 16: Jhug nov11-google guice

Applied Guice: the machinery

public class AppModule extends AbstractModule { protected void configure() { bind(Greeter.class).to(WelcomeGreeter.class); }}

public class Bootstrap { public static void main(String[] args) { Injector in = Guice.createInjector(new AppModule()); Main app = in.getInstance(Main.class); app.doIt(); }}

Page 17: Jhug nov11-google guice

Applied Guice: first notes

●@Inject is the new new● configuration involves creating bindings that is mappings

between types and their implementations● dependencies resolutions are based on types.

○ types are the natural currency of java (Bob Lee)○ type safety -> usage, documentation, IDEs, refactoring○ compare with spring which uses string identifiers

● dependencies bindings are grouped in modules○ enhances java rudimentary module system○ provides a unit of reuse. Programmer decides granularity○ modules and applications are M:N○ good practice: export interface of modules

Page 18: Jhug nov11-google guice

Applied Guice: first facts

● configuration is in plain java only. No XML○ XML is verbose, not type safe, not easily handled by

tools, eventually becomes a configuration language (XBean, namespaces <Server> <Queue> <Listener> etc) and programmer looses insight of (a probably bad) API

○ java is a type safe language supported by good IDEs○ A good design supports tools well does not need them

● Guice provides an injector not a container. It just gives you objects. There is not sleight of hand like life cycle callbacks, implicit calls start(), implicit wirings, object scanning etc

Page 19: Jhug nov11-google guice

Applied Guice: first problem

public class FarewellGreeter implements Greeter { public void greet() { System.out.println("Good bye\n"); }}

// what does this print?public class Main { private Greeter welcome; private Greeter farewell;

@Inject public void setWelcomeGreeter(Greeter gt) {this.welcome = gt;}

@Inject public void setFarewellGreeter(Greeter gt) {this.farewell = gt;}

public void doIt() { welcome.greet(); farewell.greet(); }}

Page 20: Jhug nov11-google guice

Applied Guice: the club

The previous snippet prints welcome 2 times. Guice does not know anything about FarewellGreeter, it is not a member of the club in Guice argo. So we add it to the module

public class AppModule extends AbstractModule { protected void configure() { bind(Greeter.class).to(WelcomeGreeter.class); bind(Greeter.class).to(FarewellGreeter.class); }}

we rerun the program and we get....

Page 21: Jhug nov11-google guice

Applied Guice: Binding Annotations

Exception in thread "main" com.google.inject.CreationException: Guice creation errors:

1) A binding to java.lang.Greeter was already configured at AppModule.configure(AppModule.java:6). at AppModule.configure(AppModule.java:7)

Guice supports a single binding for a type in a single module. The solution is to use annotations which are type safe metadata embedded in a program.

Page 22: Jhug nov11-google guice

Applied Guice: Binding Annotations

First we create the annotations. Boilerplate code but IDE helps.

@Retention(RetentionPolicy.RUNTIME) // by JDK@Target({ElementType.PARAMETER}) // by JDK@BindingAnnotation // by Guicepublic @interface Welcome {}

@Retention(RetentionPolicy.RUNTIME) // by JDK@Target({ElementType.PARAMETER}) // by JDK@BindingAnnotation // by Guicepublic @interface Farewell {}

Then we use them in conjuction with @Inject@Inject setWelcomeGreeter(@Welcome Greeter gt) { this.welcome = gt; }

@Inject setFarewellGreeter(@Farewell Greeter gt) { this.farewell = gt; }

Page 23: Jhug nov11-google guice

Applied Guice: Binding Annotations

We update the module and run the program

bind(Greeter.class).annotatedWith(Welcome.class).to(WelcomeGreeter.class);bind(Greeter.class).annotatedWith(Farewell.class).to(FarewellGreeter.class);

And this time it runs and prints the correct messages.

Binding Annotations● A type safe alternative to convention with all the advantages● Because they are specificed in compile time they describe

flavors of implementation therefore they can be reused. ● Example @Cache @Blue @Eager @Mock @Transactional

Page 24: Jhug nov11-google guice

Applied Guice: Providers

"which dependency do you want?" "it depends!"

Providers are used to provide objects manually.

interface Provider<T> { T get();}

class TimeGreeterProvider implements Provider<Greeter> { Greeter get() { return new SmartGreeter(new Date()); }}

bind(Greeter.class).toProvider(TimeGreeterProvider.class);

Page 25: Jhug nov11-google guice

Applied Guice: Providers

When to use a provider● no access to source code so we cannot put @Inject● need for multiple instances● optional creation of objects, lazy loading● context dependent instantiation

Providers are full members of the club● They can have @Inject if they have dependencies● Providers are DI friendly

○ implement one when you have something to provide○ have injected it to you when you must be provided with

something

Page 26: Jhug nov11-google guice

Applied Guice: Scopes

Every time Guice must satisfy a dependency it creates a new instance of the object. Frequently we must reuse objects because they are either expensive to create or stateful.

A scope is a policy for reusing injected instances.Out of the box Guice provides:

● @Singleton an instance for the application lifetime● @SessionScoped an instance for the session lifetime● @RequestScoped an instance for the request lifetime

Usage is straightforwardbind(Cart.class).to(ShoppingCart.class).in(SessionScoped.class);bind(Biller.class).toInstance(MyBiller.class).in(Singleton.class);

Page 27: Jhug nov11-google guice

Google Guice: The big picture

● A binding maps a type to an implementation● A provider creates instances.● A key uniquely identifies a binding● A scope defines the lifecycle of a binding● An annotation defines the flavor of a type

Injector Binding<T>N

Key<T>

Scope

Provider<T>

Type<T>

Annotation

*

*

Page 28: Jhug nov11-google guice

Google Guice: philosophy examples

● Extreme type safety● AOP● Environment

Page 29: Jhug nov11-google guice

Extreme Type Safety

Consider the following:

// programpublic class Report { List<String> names; List<Long> ids;

@Inject public Report(List<String> names, List<Long> ids) { this.names = names; this.ids = ids; }}

// modulebind(List.class).to(ArrayList.class);

Page 30: Jhug nov11-google guice

Extreme Type Safety

Guice fully understands generics

1) No implementation for java.util.List<java.lang.Long> was bound. while locating java.util.List<java.lang.Long> for parameter 1 at Report.<init>(Report.java:11) while locating Report

2) No implementation for java.util.List<java.lang.String> was bound. while locating java.util.List<java.lang.String> for parameter 0 at Report.<init>(Report.java:11) while locating Report

Page 31: Jhug nov11-google guice

Extreme Type Safety

Guice can handle erasure

// modulebind(new TypeLiteral<List<String>>(){}) .to(new TypeLiteral<ArrayList<String>>(){});bind(new TypeLiteral<List<Long>>(){}) .to(new TypeLiteral<LinkedList<Long>>(){});

TypeLiteral<T> is provided by Guice. It is based on the work of Neal Gafter http://gafter.blogspot.com/2006/12/type-literals.html In a nutshell this is was Java 5 should have provided instead of Class<T>

Page 32: Jhug nov11-google guice

AOP

Guice implements a restricted (if we consider AspectJ) but simpler and practical AOP model, based on method interceptors. The configuration is in the same spirit as DI.

bindInterceptor( Matcher<? super Class<?>> classMatcher, // class predicate Matcher<? super Method> methodMatcher, // method predicate MethodInterceptor... interceptor);

MethodInteceptor is an interface from org.aopalliance as in Spring

The injector enhances only objects with bindings. For a concrete class you must provide an untargetted binding

bind(ServiceImpl.class);

Page 33: Jhug nov11-google guice

AOP

A real example from Guice Persistence Extension. Works by annotating methods or classes with @Transactional

// class-level @TransacationalbindInterceptor(annotatedWith(Transactional.class), any(), getTransactionInterceptor());

// method-level @TransacationalbindInterceptor(any(), annotatedWith(Transactional.class), getTransactionInterceptor());

The transaction interceptor setups JPA entity manager, binds the current transaction to the thread, delegates to the method and finally commits on successful return and rolls back on exception

Page 34: Jhug nov11-google guice

AOP

Compare with Spring

@Aspectpublic class BeforeExample { @Before("execution(* com.xyz.myapp.dao.*.*(..))") public void doAccessCheck() { // work }}

Guice is simpler to configure but supports simple casesSpring has fully supports AOP but configuration is a major issue

Guice AOP hasn't changed from the initial release

Page 35: Jhug nov11-google guice

Environment

Some examples from the Guice Javadocs. DI is viral with Guice. It stays simple and goes for maximum power-to-weight API

SpringIntegration:public static Provider<T> fromSpring(Class<T> type, String name)Creates a provider which looks up objects from Spring using the given name. Expects a binding to org.springframework.beans.factory.BeanFactory

JndiIntegrationstatic <T> Provider<T> fromJndi<Class<T>, String name)Creates a provider which looks up objects in JNDI using the given name.Requires a binding to javax.naming.Context.

Page 36: Jhug nov11-google guice

Google Guice: resources

Web site with downloads, wiki, documentation, videos, blogs http://code.google.com/p/google-guice/

Talks I highly recommend the one by Bob Lee, the creator of Guice http://www.youtube.com/watch?v=l81T1AQWX84

Books Dependency Injection by Dhanji Prasanna (+1)

Open Source Projects

http://sitebricks.org a set of libraries for web development. Hint: Have a look to the web client. Guice style API

Page 37: Jhug nov11-google guice

@JHUG @Inject List<Question>

@Speaker Provider<Answers>


Top Related