简体   繁体   English

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

[英]How can I cleanly override the default ServiceLocator used by Jersey?

I am developing an application that uses Jersey (2.5) as its REST front-end, and Jetty as embedded HTTP(S) server, both in a so-called "embedded" way, eg. 我正在开发一个应用程序,它使用Jersey(2.5)作为其REST前端,Jetty作为嵌入式HTTP(S)服务器,两者都采用所谓的“嵌入式”方式,例如。 without resorting to making .war and deploying it but through programmatic configuration of handlers, resources, injections... 不依靠制作.war并部署它,而是通过程序化配置处理程序,资源,注入......

I would like to somehow override the HK2 ServiceLocator that is used on the server side by Jersey, or possibly provide this service locator with a parent for resolving dependencies that are defined outside of the REST part of the application. 我想以某种方式覆盖Jersey在服务器端使用的HK2 ServiceLocator ,或者可能为父服务定位器提供一个父服务器来解析在应用程序的REST部分之外定义的依赖关系。 From what I see of the code, this does not seem possible: The ServiceLocator is instantiated inside the ApplicationHandler through a call to Injections : 从我看到的代码来看,这似乎是不可能的:ServiceLocator通过调用InjectionsApplicationHandler实例化:

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);
    }

And the code in Injections tells me the following: 注射中的代码告诉我以下内容:

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

which means the newly created service locator has some arbitrarily generated name and has no parent. 这意味着新创建的服务定位器具有一些任意生成的名称,并且没有父级。

Is there a (clean) way to change this behaviour so that I inject my own ServiceLocator as a parent of the application's? 有没有(干净的)方法来改变这种行为,以便我自己注入ServiceLocator作为应用程序的父类?

I know that this answer is a little late. 我知道这个答案有点晚了。 I struggled with the same issue, but in the Dropwizard framework. 我在同一个问题上挣扎,但在Dropwizard框架中。 After some debugging, I saw the some lines of code which made me happy! 经过一些调试,我看到了一些令我开心的代码!

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

This piece of code is inside of the jerseyes WebComponent constuctor. 这段代码在jerseyes WebComponent构造器中。 So the solution is to provide ServletProperties.SERVICE_LOCATOR to your ServletContext. 所以解决方案是为ServletContext提供ServletProperties.SERVICE_LOCATOR In the Dropwizard environment, I achieved it by doing 在Dropwizard环境中,我实现了它

environment.getApplicationContext().getAttributes().setAttribute(ServletProperties.SERVICE_LOCATOR, locator);

We have a similar set up, and I've managed to get our architecture working using jwells131313's new bridgeServiceLocator API. 我们有类似的设置,我已经设法使用jwells131313的新bridgeServiceLocator API来使用我们的架构。

EDIT : Note that the current HK2 bridging implementation means Singleton instances are only local to the ServiceLocator they are created in, meaning that bridged architectures can contain more than one instance of a Singleton service. 编辑:请注意,当前的HK2桥接实现意味着Singleton实例仅对其创建的ServiceLocator是本地的,这意味着桥接体系结构可以包含多个Singleton服务的实例。 Please see this question for more information and a possible workaround/alternative approach. 请参阅此问题以获取更多信息和可能的解决方法/替代方法。

EDIT #2 : The aforementioned bug in the ServiceLocator bridge has been fixed. 编辑#2:修复了ServiceLocator桥中的上述错误。 The fix will be in hk2 2.5.0-b07 or later 修复程序将在hk2 2.5.0-b07或更高版本中

Basically I created a Feature implementation to set up the bridging and registered it with Jersey (in our instance via the ServletContainer ). 基本上我创建了一个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 is then called from the application code with the ServiceLocator created by the application to manage the application resources. 然后,从应用程序代码调用setApplicationServiceLocator并使用应用程序创建的ServiceLocator来管理应用程序资源。

This means that Jersey RESTful service implementations can now simply declare fields with the @Inject annotation and access those injected resources to service requests. 这意味着Jersey RESTful服务实现现在可以简单地使用@Inject批注声明字段,并访问那些注入资源以服务请求。

You can not make one ServiceLocator the parent of another after the ServiceLocator has been created. 在创建ServiceLocator之后,您无法使一个ServiceLocator成为另一个ServiceLocator的父级。

However as of hk2 2.4.0-b11 there will be the ability to have a ServiceLocator -> ServiceLocator bridge. 但是,从hk2 2.4.0-b11开始,将能够拥有ServiceLocator - > ServiceLocator桥。 Thus all the services from your ServiceLocator can be put into the ServiceLocator of Jersey (or any other ServiceLocator). 因此,ServiceLocator的所有服务都可以放入Jersey(或任何其他ServiceLocator)的ServiceLocator中。 This is the API: bridgeServiceLocator . 这是API: bridgeServiceLocator It is in the hk2-extras module of hk2. 它位于hk2的hk2-extras模块中。

There is a version of this available in hk2 2.4.0-b10 that should work, the fully tested and documented feature will be in hk2 2.4.0-b11 在hk2 2.4.0-b10中有一个版本可以使用,完全测试和记录的功能将在hk2 2.4.0-b11

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM