Scopes

Reminder

By default, all guice beans are created in prototype scope. Guicey only force singleton scope for jersey extensions (resources and extensions))

Available scopes:

  • @Singleton - single instance per context
  • @RequestScoped - object per request (if guice filter support is not disabled)
  • @Prototype - prototype scope annotation (useful to override forced singleton scope for jersey services)

Session scope (@SessionScoped) is usually useless, because sessions are not enabled by default in dropwizard (but it is possible to enable them).

Tip

Scopes of registered beans could be checked in guice report

Prototype

Normally, prototype scope (new instance on each new injection) is the default - no need to explicitly specify it.

The only possible usage is overriding default forced singleton scope for jersey extensions. For example, resource declared like this:

@Path("/my")
public class MyResource {}

Will be singleton. Prototype scope must be explicitly declared (if required):

@Path("/my")
@Prototype
public class MyResource {}

Note

@Prototype scope annotation support is registered by guicey

Singleton

Both com.google.inject.Singleton and javax.inject.Singleton annotations could be used.

Tip

Prefer declaring @Singleton scope on all beans, except cases when different scope is required.

Request

By default, GuiceFilter is registered for both application and admin contexts. And so request (and session) scopes will be be available in both contexts.

@RequestScoped
public class MyRequestScopedBean { ... }

In order to access request scoped beans in other beans you'll need to use provider:

Provider<MyRequestScopedBean> myBeanProvider;

Some jersey objects are already bound in request scope

Context request and response objects are also available through request scope:

Provider<HttpServletRequest> requestProvider
Provider<HttpServletResponse> responseProvider

Request scope transition

This is guice feature, it is just mentioned here.

Guice could access request scoped bindings only in current thread. If you need to access request scoped binding in different thread, you need to transfer request scope into that thread:

@Singleton 
public class RequestBean {

    // provider will not work in other thread because of request scope
    @Inject
    Provider<UriInfo> uri;

    public void doSomethingInRequestScope() {
            // jersey object must be resolved inside hk request scope (to store it in guice request scope)
            // so guice could see its instance later in another thread
            uri.get();

            // wrap logic that require request scope 
            Callable<String> action = ServletScopes.transferRequest(() -> {
                // access request scoped binding in different thread 
                return uri.get().getQueryParameters().getFirst("q");
            });            
            CompletableFuture.runAsync(() -> {
                try {
                    // execute action in different thread
                    action.call();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
    }
}            

Warning

Pay attention that for jersey scope objects provider must be called first in the current thread! Guice would be able to propagate to another thread only objects already present in guice request scope. Without it, provider.get(), called under different thread would be delegated to jersey, which is not aware of this thread and so fail to provide its request scope object.

Such additional call is not required for pure guice-managed request scope objects.

Request scope simulation

Sometimes, request scoped beans may need to be used somewhere without request (for example, inside scheduled job). Of course, this is not correct situation, and the best way is to re-design services, but not always possible.

As a workaround, request scope could be simulated:

@Inject
Provider<RScopedService> service;
...
final RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try (final RequestScoper.CloseableScope ignored = scope.open()) {
  // work with request-scoped bean
  service.get().doSomething();
}

Eager singleton

By default, guicey create injector in PRODUCTION stage, so all registered singletons will be instantiated immediately.

But if you rely on guice JIT (instantiation by injection) it may defer bean creation (until it will be requested first time).

To always start beans (even in DEVELOPMENT stage) guice provide eager singleton option: bind(MyService.class).asEagerSingleton().

For cases when you don't want to manually declare bean, but require it to start with guice context you can either implement Managed or mark bean as @EagerSingleton (the latter will simply bind annotated bean as guice eager singleton instead of you).