How to get HK2 ServiceLocator in a Jersey2 ServletContainer?

人走茶凉 提交于 2019-12-10 16:46:46

问题


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 the InjectionManager.
  • In a Feature where you could get the InjectionManager through the InjectionManagerProvider 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!