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

Guice

 Guice

An introduction to the Java dependency injection framework Guice, which I held at the Iterate Weekly Breakfast Meeting 2010-04-28

Stein Magnus Jodal

May 05, 2012
Tweet

More Decks by Stein Magnus Jodal

Other Decks in Programming

Transcript

  1. Spring Framework according to random guy at Twitter Spring: java+xml

    > java! Sounds dumb and IS dumb. Protects you from: dependencies!; no protection from: 50% of your code in f’ing xml. :( @jaykreps, 2010-03-31
  2. Spring Framework modules according to Wikipedia Inversion of Control container

    (IoC) Aspect-oriented programming (AOP) Data access Transaction management Model-view-controller web framework Remote Access framework Convention-over-configuration (Roo) Batch processing Authentication and authorization (Acegi) Remote Management (JMX) Messaging (JMS) Testing support classes
  3. Guice “lightweight dependency injection framework“ Java 5 and up Created

    by Google Apache 2.0 license All configuration in code Type-safe. Supports generics and annotations Guice does approximately one sixth of what Spring does (IoC and AOP), . . . but it does its small part well, . . . and without all the XML
  4. Dependency Injection in a Context Dependency injection is one way

    to achieve the software architecture principle Inversion of Control (IoC) .NET typically uses the S L pattern Another way, popular in Java, is the F pattern
  5. Service interface public i n t e r f a

    c e BillingService { / * * * Attempts to charge the order to the c r e d i t card . Both * successful and f a i l e d transactions w i l l be recorded . * * @return a receipt of the transaction . I f the charge was * successful , the receipt w i l l be successful . Otherwise , the * receipt w i l l contain a decline note describing why the * charge f a i l e d . * / Receipt chargeOrder ( PizzaOrder order , CreditCard creditCard ) ; } Examples taken (and slightly modified) from http://code.google.com/p/google-guice/wiki/Motivation
  6. Direct constructor calls public class RealBillingService implements BillingService { public

    Receipt chargeOrder ( PizzaOrder order , CreditCard creditCard ) { CreditCardProcessor processor = new PaypalCreditCardProcessor ( ) ; TransactionLog transactionLog = new DatabaseTransactionLog ( ) ; ChargeResult result = processor . charge ( creditCard , order . getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; return result . wasSuccessful ( ) ? Receipt . forSuccessfulCharge ( order . getAmount ( ) ) : Receipt . forDeclinedCharge ( result . getDeclineMessage ( ) ) ; } } Note the use of new. How do you test this?
  7. Factories public class RealBillingService implements BillingService { public Receipt chargeOrder

    ( PizzaOrder order , CreditCard creditCard ) { CreditCardProcessor processor = CreditCardProcessorFactory . getInstance ( ) ; TransactionLog transactionLog = TransactionLogFactory . getInstance ( ) ; ChargeResult result = processor . charge ( creditCard , order . getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; return result . wasSuccessful ( ) ? Receipt . forSuccessfulCharge ( order . getAmount ( ) ) : Receipt . forDeclinedCharge ( result . getDeclineMessage ( ) ) ; } } We replaced constructor calls with factories. Is it better?
  8. Factories It is now possible to test the class without

    charging credit cards for real money. We “just” need to:
  9. Factories Add one of these for every dependency you need.

    public class CreditCardProcessorFactory { private s t a t i c CreditCardProcessor instance ; public s t a t i c void setInstance ( CreditCardProcessor ← creditCardProcessor ) { instance = creditCardProcessor ; } public s t a t i c CreditCardProcessor getInstance ( ) { i f ( instance == n u l l ) { throw new IllegalStateException ( " CreditCardProcessorFactory not i n i t i a l i z e d . " + " Did you forget to c a l l setInstance ( ) ?" ) ; } return instance ; } }
  10. Factories And remember to setup and teardown everything in each

    test case. public class RealBillingServiceTest { / / . . . f i e l d s here . . . @Before public void setUp ( ) { TransactionLogFactory . setInstance ( inMemoryTransactionLog ) ; CreditCardProcessorFactory . setInstance ( fakeCreditCardProcessor ) ; } @After public void tearDown ( ) { TransactionLogFactory . setInstance ( n u l l ) ; CreditCardProcessorFactory . setInstance ( n u l l ) ; } / / . . . tests here . . . }
  11. Manual Dependency Injection public class RealBillingService implements BillingService { private

    f i n a l CreditCardProcessor processor ; private f i n a l TransactionLog transactionLog ; public RealBillingService ( CreditCardProcessor processor , TransactionLog transactionLog ) { t h i s . processor = processor ; t h i s . transactionLog = transactionLog ; } public Receipt chargeOrder ( PizzaOrder order , CreditCard ← creditCard ) { ChargeResult result = processor . charge ( creditCard , order . ← getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; / / . . . } }
  12. Manual Dependency Injection public class RealBillingServiceTest { / / .

    . . private f i n a l InMemoryTransactionLog transactionLog = new InMemoryTransactionLog ( ) ; private f i n a l FakeCreditCardProcessor creditCardProcessor = new FakeCreditCardProcessor ( ) ; @Test public void successfulCharge ( ) { RealBillingService billingService = new RealBillingService ( creditCardProcessor , transactionLog ) ; Receipt receipt = billingService . chargeOrder ( order , ← creditCard ) ; assertTrue ( receipt . hasSuccessfulCharge ( ) ) ; } }
  13. Manual Dependency Injection What’s the status now? No factories No

    setup and teardown in tests Easy injection of dependencies through the constructor It’s testable!
  14. Dependency Injection with Guice Create a module to tell Guice

    what implementation to use for each interface. public class BillingModule extends AbstractModule { @Override protected void configure ( ) { bind ( TransactionLog . class ) . to ( DatabaseTransactionLog . class ) ; bind ( CreditCardProcessor . class ) . to ( PaypalCreditCardProcessor . class ) ; bind ( BillingService . class ) . to ( RealBillingService . class ) ; } } If you only have one implementation in your class path, Guice will choose that one for you automatically.
  15. Dependency Injection with Guice public class RealBillingService implements BillingService {

    private f i n a l CreditCardProcessor processor ; private f i n a l TransactionLog transactionLog ; @Inject public RealBillingService ( CreditCardProcessor processor , TransactionLog transactionLog ) { t h i s . processor = processor ; t h i s . transactionLog = transactionLog ; } public Receipt chargeOrder ( PizzaOrder order , CreditCard ← creditCard ) { ChargeResult result = processor . charge ( creditCard , order . ← getAmount ( ) ) ; transactionLog . logChargeResult ( result ) ; / / . . . } }
  16. Dependency Injection with Guice Finally, get the injector from Guice,

    and ask it for an instance of any interface or class which Guice has bound to an implementation. public s t a t i c void main ( String [ ] args ) { Injector injector = Guice . createInjector (new BillingModule ( ) ) ; BillingService billingService = injector . getInstance (← BillingService . class ) ; / / . . . }
  17. Dependency Injection with Guice Guice also supports . . .

    setter injection (@Inject the setter) field injection (@Inject the field) binding to instances creating new instances whenever needed (default) reusing instances within a unit of work (e.g. HTTP request) reusing instances forever (singletons) providing short-lived instances to more long-lived objects through Providers and more . . .
  18. Why Dependency Injection? Loosen the coupling between a consumer object

    and its dependencies Move the decision of what implementation of a dependency to use out of the consuming code Move the responsibility of managing the life cycle of dependencies from the consumer to a dependency injector Improve testability Reduce the amount of boilerplate code for creating objects Boilerplate means tedious Tedious means error prone
  19. Why NOT (automatic) Dependency Injection? Object instantiation and initialization happening

    “somewhere else” may seem “magic” to some developers Needs to understand both the configuration and the code to understand the application The configuration is often in XML, which usually means that you have to maintain it manually when refactoring But not in Guice
  20. Guice resources http://code.google.com/p/google-guice/ Database persistence & transaction mangement? See warp-persist

    at http://www.wideplay.com/guicewebextensions2 JUnit test runner with Guice support? http://cowwoc.blogspot.com/2008/10/ integrating-google-guice-into-junit4.html