如何实例化包含使用Guice中的地图绑定器实例化的Map实例变量的对象

时间:2017-06-26 05:54:47

标签: java dependency-injection guice

如果一个对象(让我们称之为 workController )包含一个字符串到处理程序的地图( Map<String, Handler> handlerMap ),它将使用Guice模块中的mapBinder和其他也注入的实例变量。现在,如果我想在我的代码中实例化workController(让我们说我正在创建一个依赖于 workController workConsumer workConsumerProvider 的提供程序>因此我需要实例化this并将workController提供给workConsumer的构造函数),我应该再次声明整个映射并将其传递给workController的构造函数,还是有其他方法可以解决这个问题?

考虑WorkController.java:

public class WorkController implements ActivityController {

private ObjectMapper objectMapper;

private final Map<String, Handler> handlerMap;

@Inject
public WorkController(final ObjectMapper objectMapper,
                      final Map<String, Handler> handlerMap) {
    this.objectMapper = objectMapper;
    this.handlerMap = handlerMap;
}

public void control() {
//call the handler = getHandler(string usecase)
//call the handler.handle()
}

public Handler getHandler(String useCase) {
    Handler handler = eventHandlerMap.get(useCase);
    return handler;
}

为了支持工作控制器的DI,我已经为ObjectMapper定义了提供程序,如下所示:ObjectMapperProvider.java

public class ObjectMapperProvider implements Provider<ObjectMapper> {

    @Override
    public ObjectMapper get() {
        final ObjectMapper mapper = new ObjectMapper();
        return mapper;
    }
}

使用MapBinder将地图注入相应的Guice模块内,如下所示:

public class WorkConsumerModule extends AbstractModule {

    @Override
    protected void configure() { 

       bind(WorkConsumer.class).toProvider(WorkConsumerProvider.class);

       bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class);

       final MapBinder<String, handler> mapBinder = MapBinder.newMapBinder(binder(),
            String.class, handler.class);

       //other bindings for the subject and events to be added here.

       mapBinder.addBinding(UseCaseOne.toString()).to(HandlerImplOne.class);

       mapBinder.addBinding(UseCaseTwo.toString()).to(HandlerImplTwo.class);

    }

}

现在,考虑一下WorkConsumer.java

public class WorkConsumer {

    @Inject
    public WorkConsumer(final String instanceVariableOne,
                        final String instanceVariableTwo,
                        final String instanceVariableThree,
                        final WorkController workController) {

        final FailureHandler failureHandler = new FailureHandlerImpl();
        final Consumer consumer = new Consumer(instanceVariableOne, instanceVariableTwo, instanceVariableThree, workController, failureHandler);
        consumer.start();
    }
}

现在,为了为此 WorkConsumer 注入实例变量字符串,我们创建了一个 WorkConsumerProvider 类:WorkConsumerProvider.java

public class WorkConsumerProvider implements Provider<WorkConsumer> {

    @Override
    public WorkConsumer get() {
        final WorkConsumer workconsumer
                    = new WorkConsumer(getInstanceVariableOne(),                                                                                 
                                       getInstanceVariableTwo(),                 
                                       getInstanceVariableThree(),                 
                                       getWorkController());
    return workconsumer;
}

private String getInstanceVariableOne() {
    //return these values based on configs.
}

private String getInstanceVariableTwo() {
    //return these values based on configs.
}

private String getInstanceVariableThree() {
    //return these values based on configs.
}

//This is the place where I have a doubt.
private WorkController getWorkController() {
//Should I declare a new map and populate it again in order to instantiate workController despite having populated it once inside the guice module workConsumerModule.java ?
//I haven't yet populated it here.
    return new WorkController(new ObjectMapper(), new HashMap<String, Handler>());
}

}

1 个答案:

答案 0 :(得分:1)

您可以注入您的Providers,这样您就可以注入一个完全构造和实例化的WorkController。

public class WorkConsumerProvider implements Provider<WorkConsumer> {

    private final WorkController controller;

    @Inject
    WorkConsumerProvider(WorkController controller) {
        this.controller = controller;
    }

    @Override
    public WorkConsumer get() {
        return new WorkConsumer(
            /* instance variables */,
            controller
        );
    }

    //Your instance variables
}

这会导致每个WorkConsumer共享WorkController

如果您希望每个人都有一个唯一的WorkController,您可以将实例变量更改为Provider<WorkController>并注入它。然后在controllerProvider.get()中使用WorkConsumerProvider#get()

Guice's wiki有很多好的信息,包括针对不同场景的最佳做法和示例。