如何使HK2 ServiceLocator使用来自它桥接的ServiceLocator的Singleton服务实例?

我们正在使用ExtrasUtilities.bridgeServiceLocator()将应用ServiceLocator桥接到Jersey ServiceLocator,将在一个ServiceLocator中创建的现有Singleton应用程序服务注入到Jersey RESTful Web服务中。

然而,“外部”定位器中存在的单身人士没有被使用 – 每个服务在注入泽西岛服务时都会被再次创建。 似乎Singleton只在ServiceLocator的范围内可见,即使它已被桥接。

这是预期的行为吗? 如果是这样,是否有任何方法可以改变这种行为并在桥接的ServiceLocators中拥有一个真正的Singleton?

我已将问题提取到一组测试类中,这些测试类说明了以下几点:

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

ServiceLocator桥中存在一个已修复的错误。 修复将在hk2 2.5.0-b07或更高版本!

在此期间(以及它确实是设计行为)我通过实现自己的InjectionResolver实现了一种解决方法。 它不是一个完整的解决方案,因为它只适用于注入(即对ServiceLocator.getService()的调用不会桥接),但它完成了我现在所需要的。

如果有人需要,这是课程。 而不是调用ExtrasUtilities.bridgeServiceLocator(_innerServiceLocator, _outerServiceLocator); 你调用BridgingInjectionResolver.bridgeInjection(_innerServiceLocator, _outerServiceLocator);

 @Singleton @Rank(1) public class BridgingInjectionResolver implements InjectionResolver { @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; } }