the object graph and write maintainable code @BuzzwordCompliant A dependency injector for modular java @Like The spring application context or J2EE CDI
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
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 ...
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
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)
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
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
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);
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); }
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
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
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(); } }
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
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
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(); } }
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....
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.
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; }
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
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);
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
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);
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 * *
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
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>
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);
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
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
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.
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