Cly*_*men 4 multithreading guice
我正在使用Guice的RequestScoped和Provider,以便在用户请求期间获取某些类的实例.目前工作正常.现在我想在后台线程中做一些工作,使用在请求期间创建的相同实例.但是,当我调用Provider.get()时,guice会返回错误:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
Run Code Online (Sandbox Code Playgroud)
afaik,这是因为Guice使用线程局部变量来跟踪当前请求实例,因此无法从与处理请求的线程不同的线程调用Provider.get().
如何使用Provider在新线程中获取相同的实例?有可能实现这种写作自定义范围吗?
我最近解决了这个确切的问题.你可以做一些事情.首先,阅读ServletScopes.continueRequest(),包装一个可调用的,以便它将执行,就像它在当前请求中一样.然而,这不是一个完整的解决方案,因为它不会转发@RequestScoped对象,只有基本的东西,如HttpServletResponse.那是因为@RequestScoped预期对象不是线程安全的.你有一些选择:
如果您的整个@RequestScoped层次结构只能通过HTTP响应进行计算,那么您就完成了!您将在另一个线程中获取这些对象的新实例.
您可以使用下面的代码片段显式转发所有RequestScoped对象,但需要注意的是,它们都将被热切地实例化.
我的一些@RequestScoped对象无法处理急切的实例化,因为它们仅适用于某些请求.我用自己的范围扩展了下面的解决方案@ThreadSafeRequestScoped,并且仅转发那些.
代码示例:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
@Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
@Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
@Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
@Override
public Boolean visitNoScoping() {
return false;
}
@Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4029 次 |
| 最近记录: |