Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice Request Scope: Do I need a Provider binding for a value seeded in a servlet filter?

I'm having some problems following the Guice wiki documentation for using RequestScope (https://code.google.com/p/google-guice/wiki/ServletModule#Using_RequestScope).

I am trying to set up an application where I have a request-scoped ExecutorService. My use case is patterned off the example in the documentation - I've tried to include other relevant classes for completeness.

The main difference is that I am instantiating an instance of ExecutorService within the Filter rather than pulling a literal value out of the request parameters:

@Singleton
public class ExecutorServiceScopingFilter implements Filter {

    public ExecutorService getExecutor() {
        return Executors.newFixedThreadPool(10, ThreadManager.currentRequestThreadFactory());

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        ExecutorService executor = getExecutor();

        HttpServletRequest httpRequest = (HttpServletRequest) req;
        httpRequest.setAttribute(Key.get(ExecutorService.class).toString(), executor);

        chain.doFilter(req, resp);
    }

    ...
}

In my servlet module I bind the filter:

public class MyServletModule extends ServletModule {
    @Override
    protected void configureServlets() {
        filter("/*").through(ExecutorServiceScopingFilter.class);
        ...
    }
}

And I install the module as normal in my servlet context listener (I've set up the web.xml to use the guice filter and the below listener):

public class MyServletContextListener extends GuiceServletContextListener {
    @Override
    protected Injector getInjector() {
        Injector injector = Guice.createInjector(
            Stage.PRODUCTION,
            new MyServletModule(),
            new MyExampleModule(),
            ...
        );
    }
}

I declare the provider in an un-scoped POJO:

class MyExampleImpl implements IMyExample
{
    @Inject
    protected Provider<ExecutorService> executorProvider;

    ...
}

Which I bind in a module (and is a parameter of the createInjector call in my listener above):

public class MyExampleModule extends AbstractModule {

   @Override
   protected void configure() {
        bind(IMyExample.class).to(MyExampleImpl.class);
   }
}

When I start my web app, I get the following exception:

com.google.inject.CreationException: Guice creation errors:

1) No implementation for java.util.concurrent.ExecutorService was bound. while locating com.google.inject.Provider for field at com.example.MyExampleImpl.executorProvider(MyExampleImpl.java:12) at com.example.ExampleModule.configure(ExampleModule.java:23)

1 error

I have found a related question that indicates the use of a bogus binding (Guice: Cannot inject annotated type in Request scope). The example given is:

bind(String.class)
.annotatedWith(Names.named("name"))
.toProvider(Providers.<String>of(null));

I tried this for binding the ExecutorService and get a null for the provider (so the injector is returning the declared binding instead of using the binding defined by the filter). The use of a bogus binding is never mentioned in the official documentation.

So a few questions to try and solve this problem and understand a bit more about how Guice operates:

  1. Do I need an explicit binding other than setting the attribute (in contrast to the Guice documentation)?

  2. If so, do I need to bind anything using the @RequestScope annotation?

  3. Do I need to make a provider that implements Provider?

  4. Inspecting an @Inject Injector object, I do not see the request-scoped binding for ExecutorService in the binding maps. Should I see this binding?

  5. Inspecting the requestScopeContext thread local variable in the ServletScope class at runtime, I do see the ExecutorService binding. This indicates that the binding is working, so I am not doing something (or doing something incorrectly) to access it.

like image 672
Numbat Avatar asked Apr 10 '13 15:04

Numbat


1 Answers

You don't need any values from the request to create the executor service, so you don't need a filter. Just create a provider method in one of your modules

@Provides @RequestScoped
ExecutorService provideExecutor() {
    return Executors.newFixedThreadPool(
        10, ThreadManager.currentRequestThreadFactory());
}
like image 97
NamshubWriter Avatar answered Sep 21 '22 22:09

NamshubWriter