【问题标题】:How to get HK2 ServiceLocator in a Jersey2 ServletContainer?如何在 Jersey2 ServletContainer 中获取 HK2 ServiceLocator?
【发布时间】:2017-10-19 07:51:39
【问题描述】:

我想让 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 jersey-2.0 hk2


    【解决方案1】:

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


    正如my comment here 中提到的,从 2.26 开始,Jersey 不再对 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,否则你会得到一个NPE当您尝试获取ApplicationHandler 时。这样做的问题是已经完成了很多的初始化;几乎整个应用程序都已初始化。因此,尝试添加 Guice 集成可能会也可能不会太晚。

    以下是我看到此集成完成的其他一些地方。而且我相信在您尝试在init() 末尾执行此操作之前,他们都会受到打击。

    • ResourceConfig 构造函数中,您可以在其中注入InjectionManager
    • Feature 中,您可以通过InjectionManagerProvider 静态方法获取InjectionManager
    • 我还没有看到任何实现,但我认为做桥的首选位置是ComponentProvider,正如the docs 中提到的那样。我见过的唯一实现是针对 Spring 的。您可以在jersey-spring4 中查看源代码。这可能需要更多的工作,但我认为这将是最合适的位置,因为它在所有其他先前选项之前被调用。不过,这可能不是必需的,因为我已经看到其他人侥幸逃脱了其他两个选项。

    【讨论】:

    • 谢谢,很好的回答。感谢您指出 Jersey >2.26 不再对 HK2 有硬依赖,这是从 Jersey 1.x 迁移到 2.x 的最大缺点(我们在其他任何地方都使用 Guice,因此必须让两个 DI 合作是一个痛)。
    【解决方案2】:

    同样的问题。

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

    来实现同样的目标
    InjectionMananger#getInstance(ServiceLocator.class); 
    

    这样会更整洁一些。

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

    【讨论】:

      猜你喜欢
      • 2014-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      相关资源
      最近更新 更多