我对Guice有以下问题:单例服务注入了上下文相关信息的提供者。到目前为止,上下文仅与servlet请求相关,因此我使用了@RequestScoped提供程序,我正在服务中注入此提供程序,如下所示:
@RequestScoped
public class ContextProvider<IContext> implements Provider<IContext> {
@Override
public IContext get() { ... } // returns context
}
@Singleton
public class ServiceImpl implements IService {
@Inject
private Provider<IContext> contextProvider;
}
工作正常。现在,我正在为应用程序添加后台任务处理。后台任务不是从Web请求启动的,因此我无法使用ServletScopes.scopeRequest(..)。我编写了一个自定义范围(几乎完全来自Giuce doc的BatchScoped副本),以使每个任务在其自己的范围内运行。现在的问题是 - 如何制作BatchScoped ContextProvider并配置Guice使用它?
我通过绑定EDSL进行了此尝试:
line 1 : bind(IContext.class).toProvider(ContextProvider.class).in(RequestScoped.class);
line 2 : bind(IContext.class).toProvider(BatchContextProvider.class).in(BatchScoped.class);
但Guice在第2行告诉我'已经在第1行配置了对IContext的绑定'。
问题是:使用Guice进行此类注射的正确方法是什么?
答案 0 :(得分:2)
类似的问题:Getting multiple guice singletons of the same type
一般来说,这里的问题是你想要将同一个类绑定到两个不同的提供者(和范围,但实际上除此之外)。只有在为每个注释使用唯一的绑定注释时才可以这样做:
bind(IContext.class)
.annotatedWith(MyAnnotation1.class)
.toProvider(ContextProvider.class)
.in(RequestScoped.class);
bind(IContext.class)
.annotatedWith(MyAnnotation2.class)
.toProvider(BatchContextProvider.class)
.in(BatchScoped.class);
更改注射部位以包含相关注释:
@Inject
@MyAnnotationX
private Provider<IContext> contextProvider;
答案 1 :(得分:0)
您需要一个伪请求,该请求以您的后台任务开头并保留所有请求。这就是ServletScopes.scopeRequest
的作用。
public class MyBackgroundTask extends Thread {
@Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
哦,不要忘记使用提供程序,以便延迟检索依赖项。例如,说明上一个示例,以便后台任务使用您的IContext
。
public class MyBackgroundTask extends Thread {
private Provider<IContext> contextProvider;
@Inject
public MyBackgroundTask(Provider<IContext> contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
如果您不使用提供程序,则在此示例中,将从创建后台任务的线程完成注入,该后台任务可能位于另一个范围内。
BONUS :您可能已经注意到作为参数发送到scopeRequest
方法的空地图。检查Guice javadocs。这些是您希望已经存在于虚假请求范围中的实例。根据您的IContext
,您可能需要它。