我有一个问题,我想将Spring WebMVC应用程序的某些进程外包到单独的线程中。这很容易并且有效,直到我要使用使用全局请求的类userRightService为止。这在线程中不可用,我们遇到了一个问题,这几乎可以理解。
这是我的错误:
java.lang.RuntimeException:
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'scopedTarget.userRightsService': Scope 'request' is not active
for the current thread; consider defining a scoped proxy for this bean if
you intend to refer to it from a singleton; nested exception is
java.lang.IllegalStateException: Cannot ask for request attribute -
request is not active anymore!
好的,足够清楚。我正在尝试通过实施以下解决方案来保留请求上下文:
How to enable request scope in async task executor
这是我的可运行类:
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class myThread implements Runnable {
private RequestAttributes context;
public DataExportThread(RequestAttributes context) {
this.context = context;
}
public void run() {
RequestContextHolder.setRequestAttributes(context);
产生它的地方:
final DataExportThread dataExportThread =
new myThread(RequestContextHolder.currentRequestAttributes());
final Thread thread = new Thread(myThread);
thread.setUncaughtExceptionHandler((t, e) -> {...});
thread.start();
据我了解,我们将currentRequestAttributes存储在线程中,然后在运行时将它们还原为currentRequestAttributes ...对我来说听起来很可靠,但错误仍然存在。我认为为我的案例调整解决方案时犯了一些错误。也许有人可以帮助我找到错误。
在我经历大量具有不同解决方案的stackoverflow线程之前(请参见下文),因此我可以尝试其他方法,但是对于我来说,这似乎是最清晰,最简单的方法,所以我希望有人可以帮助我找到错误在实施中进行解释,或者解释为什么这是错误的方法。
我已经尝试过此方法,但没有成功:
这很重要:
<org.springframework-version>4.3.4.RELEASE</org.springframework-version>
顺便说一句:我知道以某种方式重组应用程序会更好,线程中不需要该请求,但是在那种情况下这很复杂,我真的希望我能避免这种情况。
-
Edit1:
无法在线程中创建的Bean是这样启动的:
@Service("userRightsService")
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserRightsService {
-
Edit2:
我也尝试过这个:
但是上下文始终是空的...
答案 0 :(得分:1)
我不确定您是如何创建/注入UserRightsService
的,所以无法重现该问题,但是我有一些建议可以尝试。
我想问题是RequestAttributes
在请求结束时失效(这就是为什么异常Cannot ask for request attribute -
request is not active anymore
),这是在任务运行时发生的。
相反,您可以尝试在产生线程的位置注入UserRightsService
,然后将此实例作为参数传递给线程。这样,UserRightsService
应该可以毫无问题地创建,因为请求应该仍然可用。
即使如此,在请求结束后尝试访问RequestAttributes
可能也会失败。在那种情况下,我建议在请求结束之前(即在运行线程之前)复制所需的所有值。
如果这对您不起作用,请提供更多有关如何初始化任务中的UserRightsService
的信息。
祝你好运!
P.S .:我认为线程类中的作用域注释是无用的,因为任务对象是手动创建的,而不是由spring管理的。
答案 1 :(得分:0)
对于那些正在搜索的人。借助Master_Ex的提示,我找到了解决方案:
在可运行环境中:
private HttpServletRequest request;
public void run() {
final RequestContextListener rcl = new RequestContextListener();
final ServletContext sc = request.getServletContext();
rcl.requestInitialized(new ServletRequestEvent(sc, request));
然后在UserRightService中,我调用一个执行以下操作的函数:
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
context.setAuthentication(getDataExportAuthentication(exportingUser));
@Master_Ex的谢谢,您的帖子非常有帮助。很抱歉,我来不及给您赏金,否则我会把它标记为正确的赏金。