我在Java应用程序中使用泽西。HK2向整个应用程序提供依赖注入。HK2 RunLevel服务在应用程序服务定位器中注册,应用程序服务定位器是Jerseys服务定位器的父服务器。
+ application locator
|\- RunLevel capabilities
| - MyCustomService, @RunLevel(value=1)
\
+ jersey locator
\- jersey resource class
\ @Inject MyCustomService我的问题是,我不能从泽西岛内访问运行级范围的服务。在上面的示例中,当打开泽西资源时,MyCustomService注入失败:
java.lang.IllegalStateException:找不到org.glassfish.hk2.runlevel.RunLevel的活动上下文
原因似乎是HK2 RunLevel特性背后的服务具有可见性本地:泽西定位器不能通过其父定位器访问它们。见这里。
问题:
更新
为了给这个问题提供上下文,我使用了一种“System”风格的运行级。
ExecutorServices (运行泽西)。泽西拒绝此级别的所有传入请求。MessageListeners被附加到代理,向后台执行程序提供请求。泽西接受并处理HTTP请求。这个概念允许对可用性和长时间运行的请求进行粒度控制。关闭时,应用程序将处于运行级2,直到完成先前接受的HTTP请求并完成排队的后台任务。但是,不接受任何新的任务/请求。然后,运行级别1,0,-1,退出。
发布于 2019-11-25 20:37:43
解决方案是尊重DescriptorVisibility#LOCAL,只从管理它们的服务定位器注入依赖于RunLevelContext的服务。
这有点麻烦:
为了减少忘记这样做的危险,并将MyCustomService注入到泽西资源中,我现在已经将我的运行级范围的服务标记为DescriptorVisibility#LOCAL。这样他们就不能被球衣定位仪注射。
发布于 2019-10-29 13:30:41
更新:这不起作用!
为了教育目的,我将把它留在这里,但是不这样做!一旦从jersey的服务定位器中访问了RunLevelController,就会丢失它在其他服务定位器上管理的所有服务的跟踪。
更新端
我已经用这个黑客解决了这个问题:我故意覆盖LOCAL可见性,并将所需的描述符插入到缺少它们的服务定位器中。
public class RunLevelBridge implements Feature {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ServiceLocator sourceLocator;
public RunLevelBridge(ServiceLocator sourceLocator) {
this.sourceLocator = sourceLocator;
}
@Override
public boolean configure(FeatureContext context) {
if (sourceLocator == null) {
log.error("Unable to bridge descriptors, the source service locator cannot be null");
return false;
}
InjectionManager im = InjectionManagerProvider.getInjectionManager(context);
ServiceLocator jerseyLocator = im.getInstance(ServiceLocator.class);
if (jerseyLocator == null) {
log.error("Unable to bridge descriptors, the target service locator cannot be null");
return false;
}
if (!sourceLocator.equals(jerseyLocator.getParent())) {
ExtrasUtilities.bridgeServiceLocator(jerseyLocator, sourceLocator);
log.info("Bridge from {} into {} established", sourceLocator.getName(), jerseyLocator.getName());
}
Filter filter;
filter = BuilderHelper.createContractFilter(RunLevelContext.class.getName());
sourceLocator.getDescriptors(filter).forEach(
(descriptor) -> ServiceLocatorUtilities.addOneDescriptor(
jerseyLocator,
descriptor,
false
)
);
filter = BuilderHelper.createContractFilter(RunLevelController.class.getName());
sourceLocator.getDescriptors(filter).forEach(
(descriptor) -> ServiceLocatorUtilities.addOneDescriptor(
jerseyLocator,
descriptor,
false
)
);
log.info("Added the RunLevel feature to jersey's service locator");
return true;
}
}该桥已在ResourceConfig中注册
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig(ServiceLocator parentLocator) {
// bridge runlevel into jersey
register(new RunLevelBridge(parentLocator));
// ... other stuff ...
}
}我鼓励对这种非正统做法的反馈意见。
https://stackoverflow.com/questions/58445967
复制相似问题