How do I get the HK2 ServiceLocator to use Singleton service instances from the ServiceLocator from which it was linked?

We use ExtrasUtilities.bridgeServiceLocator()RESTful Jersey Web Services to connect existing Singleton applications created in one ServiceLocator to Jersey Web Services by connecting the ServiceLocator application to the JerseyListator service.

However, the singletones that exist in the external locator are not used - each of the services is created again when introduced to the Jersey services. Singleton seems to be available only within the ServiceLocator scope, even if it is overlapped.

Is this intended behavior? And if there is a way to change this behavior and have a true singleton through the bridge ServiceLocators?

I extracted the problem from a set of test classes that illustrate the following point:

public class BridgedServiceTest
{
  private ServiceLocator _outerServiceLocator;
  private ServiceLocator _innerServiceLocator;

  @Test
  public void testBridgedInnerServiceOK() throws Exception
  {
    ServiceLocatorFactory serviceLocatorFactory = ServiceLocatorFactory.getInstance();

    _outerServiceLocator = serviceLocatorFactory.create("Outer");
    ServiceLocatorUtilities.addClasses(_outerServiceLocator, SingletonServiceImpl.class);

    _innerServiceLocator = serviceLocatorFactory.create("Inner");
    ExtrasUtilities.bridgeServiceLocator(_innerServiceLocator, _outerServiceLocator);

    final Client client1 = new Client();
    _outerServiceLocator.inject(client1);
    assertThat(SingletonServiceImpl.instanceCount.get(), Matchers.is(1));
    client1.test();

    final Client client2 = new Client();
    _innerServiceLocator.inject(client2);
    // next line fails as instance count is 2
    assertThat(SingletonServiceImpl.instanceCount.get(), Matchers.is(1));
    client2.test();
  }

  @After
  public void tearDown() throws Exception
  {
    _innerServiceLocator.shutdown();
    _outerServiceLocator.shutdown();
  }
}

@Contract
public interface SingletonService
{
  void fulfil();
}

@Service
public class SingletonServiceImpl implements SingletonService
{
  public static AtomicInteger instanceCount = new AtomicInteger();

  @PostConstruct
  public void postConstruct()
  {
    instanceCount.incrementAndGet();
  }

  @Override
  public void fulfil()
  {
    System.out.println("Contract Fulfilled.");
  }
}

public class Client
{
  @Inject
  private SingletonService _singletonService;

  public void test()
  {
    _singletonService.fulfil();
  }

  public SingletonService getSingletonService()
  {
    return _singletonService;
  }
}
+2
2

ServiceLocator , . hk2 2.5.0-b07 !

+1

( , ), , InjectionResolver. , (.. ServiceLocator.getService() ), , .

, - . ExtrasUtilities.bridgeServiceLocator(_innerServiceLocator, _outerServiceLocator); BridgingInjectionResolver.bridgeInjection(_innerServiceLocator, _outerServiceLocator);

@Singleton
@Rank(1)
public class BridgingInjectionResolver implements InjectionResolver<Inject>
{
  @Inject
  private ServiceLocator _localServiceLocator;

  private ServiceLocator _remoteServiceLocator;

  public BridgingInjectionResolver()
  {
  }

  /**
   * This method will bridge injection of all non-local services from the from ServiceLocator into the into
   * ServiceLocator.  The two ServiceLocators involved must not have a parent/child relationship
   *
   * @param into The non-null ServiceLocator that will be able to inject services from the from ServiceLocator
   * @param from The non-null ServiceLocator that will provide services for injection to the into ServiceLocator
   */
  public static void bridgeInjection(ServiceLocator into, ServiceLocator from)
  {
    checkParentage(into, from);
    checkParentage(from, into);
    ServiceLocatorUtilities.addClasses(into, BridgingInjectionResolver.class);
    into.getService(BridgingInjectionResolver.class).setRemoteServiceLocator(from);
  }

  private static void checkParentage(ServiceLocator a, ServiceLocator b)
  {
    ServiceLocator originalA = a;

    while (a != null) {
      if (a.getLocatorId() == b.getLocatorId()) {
        throw new IllegalStateException("Locator " + originalA + " is a child of or is the same as locator " + b);
      }

      a = a.getParent();
    }
  }

  @Override
  public Object resolve(Injectee injectee, ServiceHandle<?> root)
  {
    ActiveDescriptor<?> ad = _localServiceLocator.getInjecteeDescriptor(injectee);
    if (ad != null) {
      return _localServiceLocator.getService(ad, root, injectee);
    }
    ad = _remoteServiceLocator.getInjecteeDescriptor(injectee);
    if ((ad != null) && (ad.getDescriptorVisibility() == DescriptorVisibility.LOCAL)) {
      ad = null;
    }
    if (ad == null) {
      if (injectee.isOptional()) {
        return null;
      }

      throw new MultiException(new UnsatisfiedDependencyException(injectee));
    }
    return _remoteServiceLocator.getService(ad, root, injectee);
  }

  @Override
  public boolean isConstructorParameterIndicator()
  {
    return false;
  }

  @Override
  public boolean isMethodParameterIndicator()
  {
    return false;
  }

  private void setRemoteServiceLocator(ServiceLocator remoteServiceLocator)
  {
    _remoteServiceLocator = remoteServiceLocator;
  }

}
+2

Source: https://habr.com/ru/post/1537531/


All Articles