问题
I'd like to get Jersey2 and Guice to cooperate together, which is apparently rather difficult. I've seen some solution to this involving using the HK2-to-Guice bridge. But the bridge rely on getting the HK2 ServiceLocator
instance in the init()
of a custom Jersey2 ServletContainer
in order to initialize GuiceBrige
:
public class MyServletContainer extends ServletContainer {
@Override public void init() {
ServiceLocator sloc = getApplicationHandler().getServiceLocator();
...
} }
But somehow in the latests version of Jersey (2.26), the getServiceLocator()
does not longer exists in ApplicationHandler
. How can I get it in this context?
回答1:
Disclaimer: I don't use Guice, so this is not something that I have tested. So I don't know if what the OP is trying to do will even work. I am simply answering the main question of how to get the ServiceLocator.
As mentioned in my comment here, starting 2.26, Jersey no longer has a hard dependency on HK2. So throughout its codebase, you will no longer see a reference to a ServiceLocator
, but instead, a higher level InjectionManager
. The InjectionManager
has the same purpose as the ServiceLocator
, but the abstraction allows for different implementations of the dependency injection provider. This is why, when using 2.26, we need to add the jersey-hk2
dependency. This is the HK2 implementation of the InjectionManager
. In this implementation, the InjectionManager
will simply delegate calls to the underlying ServiceLocator
where appropriate.
That being said, the ApplicationHandler
gives you access to the InjectionManager
now, rather than the ServiceLocator
. The ServiceLocator
itself is a service, so if you have a locator you could do the following (which is pointless, but it just shows my point)
ServiceLocator locator = getServiceLocator();
locator = locator.getService(ServiceLocator.class);
This means that you can also get the locator from the InjectionManager
, which is just a high level delegator for the underlying locator
InjectionManager im = getApplicationHandler().getInjectionManager();
ServiceLocator locator = im.getInstance(ServiceLocator.class);
One thing that needs to be pointed out, and the main reason for my disclaimer is that you need to call super.init()
first in your init()
method, or else you will get an NPE when you try to get the ApplicationHandler
. The problem with this is that there is alot of initialization done; pretty much the entire application is initialized. So it may or may not be too late to try and add your Guice integration.
Here are some other places where I have seen this integration done. And I believe they would all be hit before you trying to do it at the end of the init()
.
- In a
ResourceConfig
constructor, where you could inject theInjectionManager
. - In a
Feature
where you could get theInjectionManager
through theInjectionManagerProvider
static method. - I have not seen any implementation of this, but I think the preferred location to do the bridge would be in a
ComponentProvider
, as mentioned in the docs. The only implementation I have seen is for Spring. You can see the source in the jersey-spring4. This is probably requires more work, but I think it would be the most appropriate location, as it is called before all the other previous options. It may not be required though, as I've seen others get away with the other two options.
回答2:
Same problem here.
I ended up registering the ServiceLocator -- which I injected from my javax.ws.rs.core.Application
subclass -- in a global static class and hoping that it was available at the right time. It was and it worked, but I didn't know I could have achieved the same thing by using
InjectionMananger#getInstance(ServiceLocator.class);
it's a bit tidier that way.
An alternative is to put the class name of an implementation of ServiceLocatorGenerator
in META-INF/services. this will get you control of the root service locator for the entire application before it ever reaches Jersey. The issue here is that the single method that must be overridden must return a new ServiceLocator
object but you can't use ServiceLocatorFactory
to create this object since it causes infinite recursion. So you must create and configure a ServiceLocatorImpl
which is quite involved. However, a ServiceLocatorGeneratorImpl
exists which can simply be copied from github and used as your implementation. You can bridge Guice to HK2 here before anything else happens. I haven't tried it yet but will soon.
来源:https://stackoverflow.com/questions/46825067/how-to-get-hk2-servicelocator-in-a-jersey2-servletcontainer