简体   繁体   中英

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. without resorting to making .war and deploying it but through programmatic configuration of handlers, resources, injections...

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. From what I see of the code, this does not seem possible: The ServiceLocator is instantiated inside the ApplicationHandler through a call to Injections :

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?

I know that this answer is a little late. I struggled with the same issue, but in the Dropwizard framework. 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. So the solution is to provide ServletProperties.SERVICE_LOCATOR to your ServletContext. In the Dropwizard environment, I achieved it by doing

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.

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. 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. The fix will be in hk2 2.5.0-b07 or later

Basically I created a Feature implementation to set up the bridging and registered it with Jersey (in our instance via the 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.

This means that Jersey RESTful service implementations can now simply declare fields with the @Inject annotation and access those injected resources to service requests.

You can not make one ServiceLocator the parent of another after the ServiceLocator has been created.

However as of hk2 2.4.0-b11 there will be the ability to have a ServiceLocator -> ServiceLocator bridge. Thus all the services from your ServiceLocator can be put into the ServiceLocator of Jersey (or any other ServiceLocator). This is the API: bridgeServiceLocator . It is in the hk2-extras module of hk2.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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