Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Google Guice

Google Guice

A presentation about Google Guice at jhug (http://www.jhug.gr/) November 2011

Spyros Anastasopoulos

November 12, 2011
Tweet

More Decks by Spyros Anastasopoulos

Other Decks in Programming

Transcript

  1. What is Google Guice @Simply A library that helps manipulate

    the object graph and write maintainable code @BuzzwordCompliant A dependency injector for modular java @Like The spring application context or J2EE CDI
  2. 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); } }
  3. 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 Adapter Logger Storage
  4. 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 ...
  5. 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
  6. 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)
  7. 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
  8. 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
  9. 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);
  10. 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); }
  11. 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
  12. 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
  13. 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(); } }
  14. 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(); } }
  15. 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(); } }
  16. 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
  17. 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
  18. 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(); } }
  19. 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....
  20. 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.
  21. 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 Guice public @interface Welcome {} @Retention(RetentionPolicy.RUNTIME) // by JDK @Target({ElementType.PARAMETER}) // by JDK @BindingAnnotation // by Guice public @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; }
  22. 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
  23. 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);
  24. 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
  25. 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 straightforward bind(Cart.class).to(ShoppingCart.class).in(SessionScoped.class); bind(Biller.class).toInstance(MyBiller.class).in(Singleton.class);
  26. 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 * *
  27. Extreme Type Safety Consider the following: // program public class

    Report { List<String> names; List<Long> ids; @Inject public Report(List<String> names, List<Long> ids) { this.names = names; this.ids = ids; } } // module bind(List.class).to(ArrayList.class);
  28. 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
  29. Extreme Type Safety Guice can handle erasure // module bind(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>
  30. 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);
  31. AOP A real example from Guice Persistence Extension. Works by

    annotating methods or classes with @Transactional // class-level @Transacational bindInterceptor(annotatedWith(Transactional.class), any(), getTransactionInterceptor()); // method-level @Transacational bindInterceptor(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
  32. AOP Compare with Spring @Aspect public class BeforeExample { @Before("execution(*

    com.xyz.myapp.dao.*.*(..))") public void doAccessCheck() { // work } } Guice is simpler to configure but supports simple cases Spring has fully supports AOP but configuration is a major issue Guice AOP hasn't changed from the initial release
  33. 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 JndiIntegration static <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.
  34. 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