如何干净地覆盖Jersey使用的默认ServiceLocator?

时间:2014-04-22 15:46:58

标签: java rest jersey jersey-2.0

我正在开发一个应用程序,它使用Jersey(2.5)作为其REST前端,Jetty作为嵌入式HTTP(S)服务器,两者都采用所谓的“嵌入式”方式,例如。不依靠制作.war并部署它,而是通过处理程序,资源,注入的程序化配置......

我想以某种方式覆盖Jersey在服务器端使用的HK2 ServiceLocator,或者可能为父服务定位器提供一个父服务器来解析在应用程序的REST部分之外定义的依赖关系。从我看到的代码来看,这似乎不可能:通过调用ApplicationHandlerInjections内实例化ServiceLocator:

if (customBinder == null) {
        this.locator = Injections.createLocator(new ServerBinder(application.getProperties()), new ApplicationBinder());
    } else {
        this.locator = Injections.createLocator(new ServerBinder(application.getProperties()), new ApplicationBinder(),
                                                customBinder);
    }

注射中的代码告诉我以下内容:

 public static ServiceLocator createLocator(Binder... binders) {
    return _createLocator(null, null, binders);
 }

这意味着新创建的服务定位器具有一些任意生成的名称,并且没有父级。

是否有(干净的)方法来更改此行为,以便我将自己的ServiceLocator注入应用程序的父级?

3 个答案:

答案 0 :(得分:5)

我知道这个答案有点晚了。我在同一个问题上挣扎,但在Dropwizard框架中。经过一些调试后,我看到了一些令我满意的代码:

final ServiceLocator locator = (ServiceLocator) webConfig.getServletContext()
            .getAttribute(ServletProperties.SERVICE_LOCATOR);

这段代码位于jerseyes WebComponent构造函数内部。因此,解决方案是为您的ServletContext提供ServletProperties.SERVICE_LOCATOR。在Dropwizard环境中,我通过

实现了它
environment.getApplicationContext().getAttributes().setAttribute(ServletProperties.SERVICE_LOCATOR, locator);

答案 1 :(得分:3)

我们有类似的设置,并且我设法使用jwells131313的新bridgeServiceLocator API来使用我们的架构。

编辑:请注意,当前的HK2桥接实现意味着Singleton实例仅对其创建的ServiceLocator是本地的,这意味着桥接体系结构可以包含多个Singleton服务的实例。有关详细信息和可能的解决方法/替代方法,请参阅this question

编辑#2:修复了ServiceLocator网桥中的上述错误。修复程序将在hk2 2.5.0-b07或更高版本

基本上我创建了一个Feature实现来设置桥接并将其注册到Jersey(在我们的实例中通过ServletContainer)。

public class InjectionBridge implements Feature
{
  private static ServiceLocator _applicationServiceLocator;

  private final ServiceLocator _serviceLocator;

  @Inject
  private InjectionBridge(ServiceLocator serviceLocator)
  {
    _serviceLocator = serviceLocator;
  }

  @Override
  public boolean configure(FeatureContext context)
  {
    if (_applicationServiceLocator != null)
      ExtrasUtilities.bridgeServiceLocator(_serviceLocator, _applicationServiceLocator);
    return true;
  }

  public static void setApplicationServiceLocator(ServiceLocator applicationServiceLocator)
  {
    _applicationServiceLocator = applicationServiceLocator;
  }
}
然后从应用程序代码调用

setApplicationServiceLocator,并使用应用程序创建的ServiceLocator来管理应用程序资源。

这意味着Jersey RESTful服务实现现在可以简单地声明带有@Inject注释的字段,并访问那些注入资源以服务请求。

答案 2 :(得分:2)

在创建ServiceLocator之后,您无法使一个ServiceLocator成为另一个ServiceLocator的父级。

然而,从hk2 2.4.0-b11开始,将有能力拥有ServiceLocator - > ServiceLocator桥。因此,ServiceLocator的所有服务都可以放入Jersey(或任何其他ServiceLocator)的ServiceLocator中。这是API:bridgeServiceLocator。它位于hk2的hk2-extras模块中。

hk2 2.4.0-b10中有一个版本可供使用,经过全面测试和记录的功能将在hk2 2.4.0-b11中