2016-08-26 4 views
1

В моем приложении есть несколько модулей, связывающих что-то с определенным именем или классом. Есть ли способ рассказать Guice, какие модули он должен использовать при разрешении зависимостей для инъекции.Guice указать модули для инъекций

Мой упрощенный график зависимостей выглядит примерно так, где синий указывает классы из модуля 1, а красный указывает классы из модуля 2. Теперь я хочу, чтобы создал два экземпляра из класса A, но с разными классами, связанными с некоторыми зависимостями.

Dependencies

public class Module1 extends AbstractModule { 
    @Override 
    protected void configure() { 
     bind(C.class).to(C_Impl1.class) 
     bind(D.class).to(D_Impl1.class) 
    } 
} 


public class Module2 extends AbstractModule { 
    @Override 
    protected void configure() { 
     bind(C.class).to(C_Impl2.class) 
     bind(D.class).to(D_Impl2.class) 
    } 
} 

public class Application { 
    @Inject @UseModules(Module1, ...) private final A someClassUsingImpl1; 
    @Inject @UseModules(Module2, ...) private final A someClassUsingImpl2; 

    public void doSomethingWithImpl1() { 
     someClassUsingImpl1.doSomething() 
    } 

    public void doSomethingWithImpl2() { 
     someClassUsingImpl2.doSomething() 
    } 
} 

ответ

1

Это проблема private modules были построены для. Вам все равно придется использовать привязку для аннотации, чтобы отличить, запрашиваете ли вы Impl1 версию A или версию Impl2A.

/** Marks Impl1 classes. Inject @Impl1 A to get A using C_Impl1 and D_Impl1. */ 
@BindingAnnotation 
@Retention(RetentionPolicy.RUNTIME) 
@interface Impl1 {} 

/** Marks Impl2 classes. Inject @Impl2 A to get A using C_Impl2 and D_Impl2. */ 
@BindingAnnotation 
@Retention(RetentionPolicy.RUNTIME) 
@interface Impl2 {} 

/** This is now a PrivateModule. Only exposed bindings can be used outside. */ 
public class Module1 extends PrivateModule { 
    @Override 
    protected void configure() { 
     // Bind C and D as you had before. 
     bind(C.class).to(C_Impl1.class); 
     bind(D.class).to(D_Impl1.class); 
     // Here's the tricky part: You're binding "@Impl1 A" to 
     // "A" without a binding annotation, but only in here. 
     bind(A.class).annotatedWith(Impl1.class).to(A.class); 
     // Now you expose @Impl1 A, so it can be used outside. 
     // As long as A, C, and D are only bound within private modules, 
     // they won't conflict with one another, and @Impl1 A is unique. 
     expose(A.class).annotatedWith(Impl1.class); 
    } 
} 

/** Treat Module2 the same way, as a private module. */ 

public class Application { 
    @Inject @Impl1 private final A someClassUsingImpl1; 
    @Inject @Impl2 private final A someClassUsingImpl2; 
    // ... 
} 

Если это общий шаблон для вас, создать общую PrivateModule, который принимает в классах, которые изменяются в качестве параметров конструктора, так что вам не нужно повторять себя. Они могут быть добавлены к инжектору верхнего уровня, или installed within other modules.

Injector injector = Guice.createInjector(new YourMainModule(), 
    new ImplModule(Impl1.class, C_Impl1.class, D_Impl1.class), 
    new ImplModule(Impl2.class, C_Impl2.class, D_Impl2.class));