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. Google Guice
    JHUG November 2011
    Anastasopoulos Spyros
    [email protected]

    View Slide

  2. 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

    View Slide

  3. The Object Graph
    A java program creates, wires and uses objects.
    // grep
    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);
    }
    }

    View Slide

  4. 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

    View Slide

  5. 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 ...

    View Slide

  6. 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

    View Slide

  7. 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)

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

  10. 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);

    View Slide

  11. DI with Spring
    Write an XML configuration file






    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);
    }

    View Slide

  12. 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

    View Slide

  13. 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

    View Slide

  14. 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();
    }
    }

    View Slide

  15. 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();
    }
    }

    View Slide

  16. 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();
    }
    }

    View Slide

  17. 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

    View Slide

  18. 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 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

    View Slide

  19. 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();
    }
    }

    View Slide

  20. 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....

    View Slide

  21. 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.

    View Slide

  22. 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; }

    View Slide

  23. 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

    View Slide

  24. Applied Guice: Providers
    "which dependency do you want?"
    "it depends!"
    Providers are used to provide objects manually.
    interface Provider {
    T get();
    }
    class TimeGreeterProvider implements Provider {
    Greeter get() {
    return new SmartGreeter(new Date());
    }
    }
    bind(Greeter.class).toProvider(TimeGreeterProvider.class);

    View Slide

  25. 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

    View Slide

  26. 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);

    View Slide

  27. 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
    N
    Key
    Scope
    Provider
    Type
    Annotation
    *
    *

    View Slide

  28. Google Guice: philosophy examples
    ●Extreme type safety
    ●AOP
    ●Environment

    View Slide

  29. Extreme Type Safety
    Consider the following:
    // program
    public class Report {
    List names;
    List ids;
    @Inject
    public Report(List names, List ids) {
    this.names = names;
    this.ids = ids;
    }
    }
    // module
    bind(List.class).to(ArrayList.class);

    View Slide

  30. Extreme Type Safety
    Guice fully understands generics
    1) No implementation for java.util.List was bound.
    while locating java.util.List
    for parameter 1 at Report.(Report.java:11)
    while locating Report
    2) No implementation for java.util.List was bound.
    while locating java.util.List
    for parameter 0 at Report.(Report.java:11)
    while locating Report

    View Slide

  31. Extreme Type Safety
    Guice can handle erasure
    // module
    bind(new TypeLiteral>(){})
    .to(new TypeLiteral>(){});
    bind(new TypeLiteral>(){})
    .to(new TypeLiteral>(){});
    TypeLiteral 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

    View Slide

  32. 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);

    View Slide

  33. 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

    View Slide

  34. 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

    View Slide

  35. 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 fromSpring(Class 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 Provider fromJndi, String name)
    Creates a provider which looks up objects in JNDI using the given name.Requires a
    binding to javax.naming.Context.

    View Slide

  36. 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

    View Slide

  37. @JHUG @Inject List
    @Speaker Provider

    View Slide