dependency injection con guice - gtug

37
Dependency Injection con Guice @jordi9 23 octubre 2010

Upload: jordi-gerona

Post on 15-Jan-2015

704 views

Category:

Documents


7 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Dependency Injection con Guice - GTUG

Dependency Injection con Guice

@jordi923 octubre 2010

Page 2: Dependency Injection con Guice - GTUG

roadmapMotivación

Problema

3 aproximaciones y media

Más DI con Guice

Unit Testing

Conclusiones

#bcngtug #guice

Page 3: Dependency Injection con Guice - GTUG

motivación

Page 4: Dependency Injection con Guice - GTUG

diseño

Diseño típico de una aplicación

Page 5: Dependency Injection con Guice - GTUG

problema común

Cómo obtienen los clientes los servicios?

Page 6: Dependency Injection con Guice - GTUG

3 aproximaciones y media

The Factory Pattern (Patrón Fábrica)        + Service Locator

Dependency Injection a mano

Dependency Injection con Guice

Page 7: Dependency Injection con Guice - GTUG

parte constante

public interface Dictionary {    void spellchecking(Text text);}   public class CatalanDictionary        implements Dictionary {     @Override    public void spellchecking(Text text) {        // comprobación en catalán    } }

Cualquier servicio se mantiene independientemente de la aproximación

Page 8: Dependency Injection con Guice - GTUG

Aproximación #1

The Factory Pattern

Page 9: Dependency Injection con Guice - GTUG

factory pattern / client

public class PhoneClient {         Dictionary dictionary;

    public void sendSMS(Text text) {        dictionary = DictionaryFactory.getInstance();        dictionary.spellchecking(text);      }

}

Page 10: Dependency Injection con Guice - GTUG

factory pattern / servicepublic static class DictionaryFactory {    static class DictionaryHolder {        static Dictionary instance = new CatalanDictionary();     }

    public static Dictionary getInstance() {        return DictionaryHolder.instance;     }

   public static void setInstance(Dictionary mock) {        DictionaryHolder.instance = mock;    }}

Page 11: Dependency Injection con Guice - GTUG

factory pattern / consideraciones

Hay que escribir una fábrica para cada objeto y para cada dependencia - boilerplate code

Hay que escribir una fábrica para cada variación en las dependencias.

El cliente establece sus dependencias en tiempo de compilación - Están encapsuladas.

Propagación viral de clases estáticas - static Difícil reutilizar el código cliente en otro contexto.

Hay que modificar el código para poder hacer unit testing.

Page 12: Dependency Injection con Guice - GTUG

Aproximación #1.5

Service Locator

Page 13: Dependency Injection con Guice - GTUG

service locator

Tipo especial de fábrica.    Hereda casi todos sus problemas.     Introduce nuevos problemas. eg: no type-safety

Dictionary dictionary = (Dictionary) new ServiceLocator()                                    .get("CatalanDictionary");  

Page 14: Dependency Injection con Guice - GTUG

Aproximación #2

Dependency Injection a mano

Page 15: Dependency Injection con Guice - GTUG

el principio de hollywood

public class PhoneClient {

    private final Dictionary dictionary;     public PhoneClient(Dictionary dictionary) {        this.dictionary = dictionary    }

    public void sendSMS(Text text) {        dictionary.spellchecking(text);      }

}

"Don't call us, we'll call you"

Page 16: Dependency Injection con Guice - GTUG

DI manual / ventajas

No podemos crear un cliente sin los servicios necesarios. Dependencias claras.

Podemos reutilizar el cliente con múltiples implementaciones de un mismo servicio. Las dependencias pasan de estar en tiempo de compilación a estar a nivel de de aplicación.

La clase es testeable.

  Pero aun tenemos que escribir más codigo fábrica! 

Page 17: Dependency Injection con Guice - GTUG

Aproximación #3

Dependency Injection con Guice

Page 18: Dependency Injection con Guice - GTUG

Google GuiceFramework de DI creado por Google (2007).

Toda aplicación Java lo utilitza: Google Docs, GMail, Adwords...

objetivos    Evitar escribir fábricas y boilerplate code

    Más comprobaciones de tipos - Type safety

    Flexibilidad y facilidad para escribir buen código

Page 19: Dependency Injection con Guice - GTUG

@Inject

public class PhoneClient {

    private final Dictionary dictionary;     @Inject     public PhoneClient(Dictionary dictionary) {        this.dictionary = dictionary    }

    public void sendSMS(Text text) {        dictionary.spellchecking(text);      }

}

Aplicamos @Inject para obtener las dependencias.

Page 20: Dependency Injection con Guice - GTUG

@Injections

@Inject private Dictionary dictionary;

field injection

method injection@Inject public void setDictionary(Dictionary dictionary) {    this.dictionary = dictionary;}

constructor injectionpublic class PhoneClient {    private final Dictionary dictionary;     @Inject     public PhoneClient(Dictionary dictionary) {        this.dictionary = dictionary    }}

Page 21: Dependency Injection con Guice - GTUG

modules

public class DictionaryModule extends AbstractModule {    protected void configure() {       bind(Dictionary.class).to(CatalanDictionary.class);     }}

Tenemos Modules que configuran Guice.   no XML... yay!

public class DictionaryModule implements Module {    public void configure(Binder binder) {      binder.bind(Dictionary.class).to(CatalanDictionary.class);     }}

versión DRY (Don't Repeat Yourself)

versión JIT (Just In Time)

@ImplementedBy(CatalanDictionary.class)public class Dictionary {}

Page 22: Dependency Injection con Guice - GTUG

bootstrappingIniciando una aplicaciónpublic class PhoneRunner {    public static void main(String[] args) {        Injector injector = Guice                        .createInjector(new DictionaryModule());        PhoneClient phone = Injector                        .getInstance(PhoneClient.class);

        phone.sendSMS(new Text("foo text"));    }}

consideraciones    @Inject es viral.         Solo una clase debería tratar con el Injector.

Page 23: Dependency Injection con Guice - GTUG

más Guice i DI…

Page 24: Dependency Injection con Guice - GTUG

múltiples implementaciones

public class DictionaryModule extends AbstractModule {    protected void configure() {          bind(Dictionary.class)            .annotatedWith(Catalan.class)            .to(CatalanDictionary.class);     }}

Binding annotationspublic class PhoneClient {    private final Dictionary dictionary;

    @Inject     public PhoneClient(@Catalan Dictionary dictionary) {        this.dictionary = dictionary

    }}

Hay que configurarlo en un Module

Page 25: Dependency Injection con Guice - GTUG

provider patternServicios que dependen del tiempo de ejecución, de librerias de terceros o que se acaban

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

public class CoffeeJunkie {    CupOfCoffee cupOfcoffee;    @Inject    public CoffeeJunkie(CupOfCoffee cupOfcoffee) {        this.cupOfcoffee = cupOfcoffee;       }     public void drinkTwoCupsOfCoffe() {        cupOfcoffee.drink();        cupOfcoffee.drink(); // <-- is empty!    }}

Page 26: Dependency Injection con Guice - GTUG

provider injection

public class CoffeeModule extends AbstractModule {   protected void configure() {   bind(CupOfCoffee.class).toProvider(new Provider<CupOfCoffee>() {        public CupOfCoffee get() {            return new CupOfCoffe(); // cuidado con el new!        }      });    }}

public class CoffeeJunkie {    Provider<CupOfCoffee> cupsProvider;    @Inject    public CoffeeJunkie(Provider<CupOfCoffee> cupOfcoffee) {        this.cupsProvider = cupsProvider;       }     public void drinkTwoCupsOfCoffe() {        cupsProvider.get().drink();        cupsProvider.get().drink(); // <-- ok!    }}

Page 27: Dependency Injection con Guice - GTUG

@Providessince guice 2.0

Métodos que nos dan un objeto en concreto. Tienen que estar en un Module

public class CoffeeModule extends AbstractModule {   protected void configure() {     // ...   }

   @Provides @WithMilk   public CupOfCoffee provideCupOfCoffeWithMilk() {        return new CupOfCoffe.builder().withMilk().build();   }}

Page 28: Dependency Injection con Guice - GTUG

scopesPolítica de reutilización de instancias    No-scope (por defecto)    Singleton    Web: RequestScope, SessionScope...

@Singleton public class CatalanDictionary ... {     ... }

public class DictionaryModule extends AbstractModule {    protected void configure() {        bind(Dictionary.class)            .to(CatalanDictionary.class)            .in(Scopes.SINGLETON);     }}

o en un Module

Page 29: Dependency Injection con Guice - GTUG

otras característicasAspect Oriented Programming    con AOP Allicance

bindInterceptor(    Matchers.any(), // classes     Matchers.annotatedWith(Foo.class), // methods    new FooInterceptor() // interceptor); 

Cargar constantes con comprobaciones de tipo.    gtug.properties -> String gtug; int members;

 Injections opcionales, estáticas, ...    @Inject(optional=true) Date launchDate;

Integraciones:    JNDI, Spring, JMX, Struts2, OSGi...

Page 30: Dependency Injection con Guice - GTUG

guice 2.0Multibindings   Hello Multibinder y MapBinder / útil para plugins

@Inject ImageFinder(Set<UriBuilder> uriBuilders) { ... }

// modulepublic void configure() {    Multibinder<UriBuilder> uriBinder =           Multibinder.newSetBinder(binder(), UriBuilder.class);    uriBinder.addBinding().to(S3UriBinder.class);}

AssistedInject   Hello @Assisted

Private modules   Soluciona el robot-legs problem: Dos grafos del mismo objeto ligeramente    distintos

Page 31: Dependency Injection con Guice - GTUG

unit testing

Page 32: Dependency Injection con Guice - GTUG

unit testing

Aplicando DI con Guice, nuestro código ya es testeable!

Código (método) que ejecuta un otro código para comprobar su validez.  funcionamientoPrecondición - Clase a testear - Postcondición (asserts)

característicasRápido, repetible, automático.

frameworksJunit, TestNG, Mockito, EasyMock, JMock

Page 33: Dependency Injection con Guice - GTUG

test con junit

public class StringsTest {     @Test    public void stripAllHTMLForAGivenText() {        String html = "<a>Link</a>";        String expected = "Link";        assertEquals(expected,Strings.stripHTML(html));    }      }

public class Strings {

    public static String stripHTML(String input) {        return input.replaceAll("</?+(\\b)[ˆ<>]++>", "");    } }

unit test

Page 34: Dependency Injection con Guice - GTUG

test con dependencias

// Class under test CreditCardProcessor creditCardProcessor;

@Testpublic void chargeCreditCard() {        creditCardProcessor = Guice.createInjector()                   .getInstance(CreditCardProcessor.class);   CreditCard c = new CreditCard("9999 0000 7777", 5, 2009);   creditCardProcessor.charge(c, 30.0);   assertThat(creditCardProcessor.balance(c), is(-30.0));}

es incorrecto!

@Inject public CreditCardProcessor(Queue queue) {    this.queue = queue; }

unit test…?

Page 35: Dependency Injection con Guice - GTUG

test con dependencias / mocks

@Testpublic void chargeCreditCard() {    Queue queue = mock(Queue.class);   CreditCard c = new CreditCard("9999 0000 7777", 5, 2009);

   creditCardProcessor = new CreditCardProcessor(queue);   creditCardProcessor.charge(c, 30.0);

   verify(queue).enqueue(c, 30.0);}

Dependencias falsas: mocks (mockito)

Page 36: Dependency Injection con Guice - GTUG

para acabar…

futuro de dependency injection    Google + SpringSource = JSR-330 acabada    Spring 3 - annotation based    Maven 3 - de plexus a guice

guice 3.0    Soporte para JSR-330    guice-persist integrado (antiguo warp-persist)    Más SPI y Extension Points

y más guice!    GIN - GWT INjection, subset de Guice    RoboGuice - Guice en Android. Inject de views, resources...

Page 37: Dependency Injection con Guice - GTUG

gracias!

[email protected]@jordi9