Search code examples
springdependency-injectionguiceguice-3

How inject 3 instances of same type with different dependence by Guice?


I am using Guice to manager my class dependence. I have a LogicHandler class which depended on several Components class.

  public interface LogicHandler {
      private Component component1;
      private Component component2;
      private Component component3;
  }

  public interface Component {
      public String doWork();
  }

I will have 3 instances of LoigcHanlder. Using which instance will be decided in run time. Each of instance will have different Component implementation and all implementation are pre-defined.

If I were using spring DI, the xml config would be look like:

<bean id="handler1" class="org.sample.handlers.DefaultHanlder">
  <property name="component1" ref="componentImplementationA" />
  <property name="component2" ref="componentImplementationB" />
  <property name="component3" ref="componentImplementationC" />
</bean>

<bean id="handler2" class="org.sample.handlers.DefaultHanlder">
  <property name="component1" ref="componentImplementationD" />
  <property name="component2" ref="componentImplementationE" />
  <property name="component3" ref="componentImplementationF" />
</bean>

<bean id="handler3" class="org.sample.handlers.DefaultHanlder">
  <property name="component1" ref="componentImplementationG" />
  <property name="component2" ref="componentImplementationH" />
  <property name="component3" ref="componentImplementationI" />
</bean>

Note: all handlers are implemented by DefaultHanlder.

Using which handler instance bases on some parameters.


Solution

  • Assuming I am understanding your question correctly, you would like to pick a particular concrete implementation to bind based on a particular parameter. One way to do this is to create a module that takes as a constructor the parameters you need for deciding which module to bind. The logic to bind the particular concrete implementation would be in the bind method of the module. E.g

    public class YourModule extends AbstractModule {
    
    Parameters settings;
    
    public YourModule(Parameters settings) {
        this.settings = settings;
    }
    
    @Override
    protected void configure() {
       if(settings.val == 1) {
          bind(DefaultHanlder.class).toInstance(ComponentA.class);
       } else if(settings.val == 2) {
          bind(DefaultHanlder.class).toInstance(ComponentB.class);
       }
       .
       .
       .
    }
    

    When you create the injector, use the YourModule module so that the right wiring is put in place. The injector then should inject the proper concrete class for DefaultHanlder without your client code knowing how to pick the right concrete implementation.

    There are probably other ways to do this as well (e.g. AssistedInjection might also work) but using a separate module is pretty straightforward.