gpt4 book ai didi

multithreading - 多线程中的 Guice 和 RequestScoped 行为

转载 作者:行者123 更新时间:2023-12-02 04:41:13 25 4
gpt4 key购买 nike

我正在使用 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.

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

关于multithreading - 多线程中的 Guice 和 RequestScoped 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37340559/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com