1

Im writing a component using Google Guice that lives next to a web application that does not use any dependency injection tool.

The Guice Module in the component has a few "fixed" bindings that will not change and a couple that are dynamic since they change in every request from the web application.

The easy (and bad) way that I solved this is that everytime that the web application asks the component to do something for the first time, the component builds the new Guice Module, creates the instance and returns it to the web app:

public static X init(@NotNull final Foo perRequestObject, @NotNull final Bar perRequestObject2)
{
    final Injector injector = Guice.createInjector(new AbstractModule()
    {
        @Override
        protected void configure()
        {
            install(new NonChanging Module());
            bind(Foo.class).toInstance(perRequestObject);
            bind(Bar.class).toInstance(perRequestObject2);
        }
    });
    return return injector.getInstance(X.class);
}

I think that this is a bad approach since building the Injector per request is expensive. What I would like to have is an injector already created that I can override at runtime. I found some stuff around:

1- Override the dynamic bindings (answer https://stackoverflow.com/a/531110/1587864). This still needs to create a new injector so I would have the same problem.

2- Implement some kind of Factory that is already binded in the Injector and has the ability to access the "dynamic" properties that come from the web application and are per request.

I'm not sure how to implement the second one, does this concept exist in Guice?

Thanks

4

1 回答 1

3

正如评论所说,完全正确的解决方案是Scope. 假设您已将本文SimpleScope中的实现复制到您的项目中,那么这就是我将在您的组件中执行的操作。正如您在上面所做的那样,我假设和是您需要基于每个请求创建的对象,并且是您最终需要 Guice 创建的事物的类。我进一步假设它上面有一个名为的方法,该方法是您希望调用以最终返回到 servlet 的方法:FooBarXXdoTheActualRequestLogic

public class MyWebComponent
{
  private final Provider<X> theGuiceCreatedObject;
  private final SimpleScope perRequestScope;

  public MyWebComponent() {
    perRequestScope = new SimpleScope();
    Injector injector = Guice.createInjector(new AbstractModule()
    {
        @Override
        protected void configure()
        {
            install(new NonChangingModule());
            bind(Foo.class).toProvider(SimpleScope.seededKeyProvider())
                .in(perRequestScope);
            bind(Bar.class).toProvider(SimpleScope.seededKeyProvider())
                .in(perRequestScope);
        }
    });
    theGuiceCreatedObject = injector.getProvider(X.class);
  }

  // I assume methods called makeFoo and makeBar that can make
  // a Foo or Bar for a request

  // called by the web service to say "handle this request"
  public RequestResult handleRequest(DataToMakeFooAndBarWith requestData) {
    try {
      perRequestScope.enter();
      perRequestScope.seed(Foo.class, makeFoo(requestData));
      perRequestScope.seed(Bar.class, makeBar(requestData));
      return theGuiceCreatedObject.get().doTheActualRequestLogic(requestData);
    } finally {
      perRequestScope.exit();
    }
  }
}
于 2014-07-12T19:54:13.680 回答