如何在 Jersey2 ServletContainer 中获取 HK2 ServiceLocator?

How to get HK2 ServiceLocator in a Jersey2 ServletContainer?

我想让Jersey2和Guice一起合作,这显然是比较困难的。我已经看到一些涉及使用 HK2-to-Guice 桥的解决方案。但是桥依赖于在自定义 Jersey2 ServletContainerinit() 中获取 HK2 ServiceLocator 实例来初始化 GuiceBrige:

public class MyServletContainer extends ServletContainer {
  @Override public void init() {
    ServiceLocator sloc = getApplicationHandler().getServiceLocator();
    ...
} }

但不知何故,在最新版本的 Jersey (2.26) 中,getServiceLocator() 不再存在于 ApplicationHandler 中。在这种情况下我怎样才能得到它?

免责声明:我不使用 Guice,所以这不是我测试过的东西。所以我不知道 OP 试图做的事情是否会奏效。我只是简单回答如何获取ServiceLocator的主要问题。


所述,从 2.26 开始,Jersey 不再 hard 依赖 HK2。因此,在其整个代码库中,您将不再看到对 ServiceLocator 的引用,而是更高级别的 InjectionManagerInjectionManagerServiceLocator 具有相同的目的,但抽象允许依赖注入提供程序的不同实现。这就是为什么在使用 2.26 时,我们需要添加 jersey-hk2 依赖。这是 InjectionManager 的 HK2 实现。在此实现中,InjectionManager 将在适当的情况下简单地将调用委托给底层 ServiceLocator

也就是说,ApplicationHandler 现在让您可以访问 InjectionManager,而不是 ServiceLocatorServiceLocator 本身就是一个服务,所以如果你有一个定位器,你可以执行以下操作(这是没有意义的,但它只是说明了我的观点)

ServiceLocator locator = getServiceLocator();
locator = locator.getService(ServiceLocator.class);

这意味着您还可以从InjectionManager获取定位器,它只是底层定位器的高级委托

InjectionManager im = getApplicationHandler().getInjectionManager();
ServiceLocator locator = im.getInstance(ServiceLocator.class);

需要指出一件事,我免责声明的主要原因是您需要在 init() 中调用 super.init() first方法,否则当您尝试获取 ApplicationHandler 时,您将获得 NPE。问题在于完成了很多的初始化;几乎整个应用程序都已初始化。因此,尝试添加您的 Guice 集成可能为时已晚,也可能不会太晚。

以下是我在其他一些地方看到此集成完成的地方。而且我相信在 init().

结束时你尝试这样做之前他们都会被击中
  • ResourceConfig 构造函数中,您可以在其中注入 InjectionManager.
  • Feature 中,您可以通过 InjectionManagerProvider 静态方法获取 InjectionManager
  • 我还没有看到这个的任何实现,但我认为做桥的首选位置是 ComponentProvider,如 the docs. The only implementation I have seen is for Spring. You can see the source in the jersey-spring4 中所述。这可能需要更多的工作,但我认为这将是最合适的位置,因为它在所有其他先前选项之前被调用。不过,这可能不是必需的,因为我看到其他人选择了其他两个选项。

同样的问题。

我最终在全局静态 class 中注册了 ServiceLocator——我从我的 javax.ws.rs.core.Application subclass 注入的,并希望它在正确的时间可用.它确实有效,但我不知道我可以通过使用

来达到同样的效果
InjectionMananger#getInstance(ServiceLocator.class); 

这样比较整洁。

另一种方法是将 class 实现 ServiceLocatorGenerator 的名称放在 META-INF/services 中。这将使您在整个应用程序到达 Jersey 之前控制根服务定位器。这里的问题是必须重写的单一方法必须 return 一个新的 ServiceLocator 对象,但是你不能使用 ServiceLocatorFactory 来创建这个对象,因为它会导致无限递归。因此,您必须创建和配置一个非常复杂的 ServiceLocatorImpl。但是,ServiceLocatorGeneratorImpl 存在,可以简单地从 github 复制并用作您的实现。在发生任何其他事情之前,您可以在此处将 Guice 桥接到 HK2。我还没有尝试过,但很快就会尝试。