作用域“会话"在当前线程中不起作用; IllegalStateException:找不到线程绑定的请求 [英] Scope 'session' is not active for the current thread; IllegalStateException: No thread-bound request found

查看:348
本文介绍了作用域“会话"在当前线程中不起作用; IllegalStateException:找不到线程绑定的请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个控制器,希望每个会话都唯一.根据spring文档,实现有两个细节:

I have a controller that I'd like to be unique per session. According to the spring documentation there are two details to the implementation:

1.初始Web配置

要在请求,会话和全局会话级别(网络范围的Bean)上支持Bean的作用域,在定义Bean之前,需要一些较小的初始配置.

To support the scoping of beans at the request, session, and global session levels (web-scoped beans), some minor initial configuration is required before you define your beans.

我已将以下内容添加到我的web.xml中,如文档所示:

I've added the following to my web.xml as shown in the documentation:

<listener>
  <listener-class>
    org.springframework.web.context.request.RequestContextListener
  </listener-class>
</listener>

2.范围豆作为依赖项

如果要将(例如)HTTP请求范围的bean注入另一个bean,则必须注入AOP代理来代替范围的bean.

If you want to inject (for example) an HTTP request scoped bean into another bean, you must inject an AOP proxy in place of the scoped bean.

我用@Scope注释了bean,提供了proxyMode,如下所示:

I've annotated the bean with @Scope providing the proxyMode as shown below:

@Controller
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ReportBuilder implements Serializable {
    ...
    ...
}

问题

尽管进行了上述配置,我还是收到以下异常:

In spite of the above configuration, I get the following exception:

org.springframework.beans.factory.BeanCreationException:创建名称为'scopedTarget.reportBuilder'的bean时出错:当前线程的作用域'session'无效;如果您打算从单例中引用它,请考虑为此bean定义作用域代理.嵌套异常为java.lang.IllegalStateException:未找到线程绑定请求:您是在实际Web请求之外引用请求属性,还是在原始接收线程之外处理请求?如果您实际上是在Web请求中操作并且仍然收到此消息,则您的代码可能在DispatcherServlet/DispatcherPortlet之外运行:在这种情况下,请使用RequestContextListener或RequestContextFilter公开当前请求.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.reportBuilder': Scope 'session' 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: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

更新1

下面是我的组件扫描.我在web.xml中有以下内容:

Below is my component scan. I have the following in web.xml:

<context-param>
  <param-name>contextClass</param-name>
  <param-value>
    org.springframework.web.context.support.AnnotationConfigWebApplicationContext
  </param-value>
</context-param>

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>org.example.AppConfig</param-value>
</context-param>

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

以及AppConfig.java中的以下内容:

@Configuration
@EnableAsync
@EnableCaching
@ComponentScan("org.example")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements AsyncConfigurer {
  ...
  ...
}

更新2

我创建了一个可复制的测试用例.这是一个较小的项目,因此存在差异,但是会发生相同的错误.有很多文件,因此我已将其作为tar.gz格式上传到

I've created a reproducible test case. This is a much smaller project, so there are differences, but the same error happens. There's quite a few files, so I've uploaded it as a tar.gz to megafileupload.

推荐答案

我正在回答自己的问题,因为它可以更好地概述原因并提供可能的解决方案.我已将奖金授予@Martin,因为他指出了原因.

I'm answering my own question because it provides a better overview of the cause and possible solutions. I've awarded the bonus to @Martin because he pin pointed the cause.

原因

如@Martin所建议,原因是使用多个线程.如

As suggested by @Martin the cause is the use of multiple threads. The request object is not available in these threads, as mentioned in the Spring Guide:

DispatcherServletRequestContextListenerRequestContextFilter都做完全相同的事情,即将HTTP请求对象绑定到为该请求提供服务的线程.这样一来,请求和会话范围内的bean就可以在调用链的下游使用.

DispatcherServlet, RequestContextListener and RequestContextFilter all do exactly the same thing, namely bind the HTTP request object to the Thread that is servicing that request. This makes beans that are request- and session-scoped available further down the call chain.

解决方案1 ​​

可以使请求对象可用于其他线程,但是它对系统有一些限制,可能并非在所有项目中都可行.我从>在多个线程的Web应用程序:

It is possible to make the request object available to other threads, but it places a couple of limitations on the system, which may not be workable in all projects. I got this solution from Accessing request scoped beans in a multi-threaded web application:

我设法解决了这个问题.我开始使用SimpleAsyncTaskExecutor而不是WorkManagerTaskExecutor/ThreadPoolExecutorFactoryBean.好处是SimpleAsyncTaskExecutor将永远不会重用线程.那只是解决方案的一半.解决方案的另一半是使用RequestContextFilter而不是RequestContextListener. RequestContextFilter(以及DispatcherServlet)具有threadContextInheritable属性,该属性基本上允许子线程继承父上下文.

I managed to get around this issue. I started using SimpleAsyncTaskExecutor instead of WorkManagerTaskExecutor / ThreadPoolExecutorFactoryBean. The benefit is that SimpleAsyncTaskExecutor will never re-use threads. That's only half the solution. The other half of the solution is to use a RequestContextFilter instead of RequestContextListener. RequestContextFilter (as well as DispatcherServlet) has a threadContextInheritable property which basically allows child threads to inherit the parent context.

解决方案2

唯一的其他选择是在请求线程内使用会话范围的Bean.就我而言,这是不可能的,因为:

The only other option is to use the session scoped bean inside the request thread. In my case this wasn't possible because:

  1. 控制器方法带有@Async注释;
  2. 控制器方法将启动批处理作业,该批处理作业将线程用于并行作业步骤.
  1. The controller method is annotated with @Async;
  2. The controller method starts a batch job which uses threads for parallel job steps.

这篇关于作用域“会话"在当前线程中不起作用; IllegalStateException:找不到线程绑定的请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆