Integration lifecycle¶
Jersey2 guice integration is more complicated than for jersey1, because of HK2 container, used by jersey2.
Note
Many people ask why not just use HK2 instead of guice as it's already provided. Unfortunately, it's hard to use it in the same elegant way as we can use guice. HK2 context is launched too late (after dropwizard run phase). For example, it is impossible to use HK2 to instantiate dropwizard managed object because managed must be registered before HK2 context starts.
Guice integration done in guice exclusive way as much as possible: everything should be managed by guice and invisibly integrated into HK2. Anyway, it is not always possible to hide integration details, especially if you need to register jersey extensions.
Tip
You can use guicey lifecycle events to see initialization stages in logs:
.printLifecyclePhases()
Lifecycle¶
- Dropwizard configuration phase (
~Application.initialize
)- Apply configuration hooks
- Guice bundle registered
- Perform classpath scan for commands (optional)
- Dropwizard run phase (
~Application.run
)- Dropwizard runs bundles (guice bundle is one of them so guice initialization may be performed between other dropwizard bundles)
- Search guicey bundles in dropwizard bundles (optional)
- Lookup guicey bundles
- Apply configuration from guicey bundles
- Injector creation (using factory)
- Bind dropwizard objects: Environment, Configuration, Bootstrap
- Scan for installers (in auto configuration mode)
- Scan for extensions (in auto configuration mode)
- Register
GuiceFeature
in environment (jerseyFeature
which will trigger jersey side installations) - Apply lazy jersey bindings
- Activate guice servlet support, register GuiceFilter on admin and main contexts (could be disabled)
- Injector created
- Call installers to register extensions
- Your application's
run
method executed. Injector is already available, so any guice bean could be accessed
- Jersey start
- Managed beans started
- HK2 context creation (jersey start)
GuiceFeature
(registered earlier) called- Optionally register HK2-guice bridge (only guice to hk2 way to let hk2 managed beans inject guice beans)
- Run jersey specific installers (resource, extension)
Note
Any EnvironmentCommand
did no start jersey, so managed objects will not be started.
Also, all jersey related extensions will not be started. Still, core guice context will be completely operable.
When guice context is created, jersey context doesn't exist and when jersey context is created it doesn't aware of guice existence.
Cross context bindings¶
Access jersey beans from guice¶
To access HK2 bindings we need HK2 ServiceLocator
: it's instance is registered by GuiceFeature
(in time of HK2 context startup).
Jersey components are bound as providers:
binder.bind(jerseyType).toProvider(new LazyJerseyProvider(jerseyType));
Internally this provider will perform lookup in HK2 service locator:
injector.getInstance(ServiceLocator.class).getService(jerseyType);
This way jersey beans are "bridged" to guice. They can't be accessed directly in guice beans at injector creation time (as there is nothing to "bridge" yet).
@Inject Provider<JerseyType> provider
must be used to access such beans.
See more details in jersey bindings module.
Access guice beans from jersey¶
Note
It's almost never required to care about beans visibility from HK2 side because guicey already did all required bindings.
HK2 could see all guice beans because of registered guice-bridge. But it doesn't mean HK2 can analyze all guice beans to search for extensions (it can resolve only direct injection).
Specific jersey installers (resource, extension) create required bindings manually in time of HK2 context creation.
Jersey extensions installer handles most specific installation cases (where HK2 knowledge is required). It uses the same technic, as the other side binding:
binder.bindFactory(new LazyGuiceProvider(guiceType)).to(type)
On request, factory will simply delegate lookup to guice injector:
injector.getInstance(guiceType);
Tip
If you just want to add some beans in HK2 context, annotate such beans with @Provider
and @HK2Managed
- provider
will be recognized by installer and HK2 managed annotation will trigger simple registration (overall it's the same
as write binding manually).
@HK2Managed
@Provider
public class MyBeanMangedByHK2 { ... }
For more details look jersey provider installer
Problematic cases¶
The problems may appear with binding of jersey extensions.
Good example is ValueFactoryProvider
. Most likely you will use AbstractValueFactoryProvider
as base class, but it declares
direct binding for MultivaluedParameterExtractorProvider
. So such bean would be impossible to create eagerly in guice context.
There are two options to solve this:
- use
@LazyBinding
: bean instance will not be created together with guice context (whenMultivaluedParameterExtractorProvider
is not available), and creation will be initiated by HK2, when binding could be resolved. - or use
@HK2Managed
this will delegate instance management to HK2, but still guice services may be injected.
Note
You may use HK2-first strategy and create all jersey
extensions in HK2 instead of guice. In this case you can use @GuiceManaged
annotation to delegate management back to guice.
In other cases simply wrap jersey specific bindings into Provider
.