Scope 'session' is not active for the current thread; IllegalStateException: No thread-bound request found 作用域为'session'的内容对于当前线程不活动;IllegalStateException: 未找到与线程绑定的请求
Scope 'session' is not active for the current thread; IllegalStateException: No thread-bound request found 作用域为'session'的内容对于当前线程不活动;IllegalStateException: 未找到与线程绑定的请求
我有一个控制器,我希望每个会话都是唯一的。根据Spring文档的说明,实现有两个关键点:
1. 初始Web配置
为了支持请求、会话和全局会话级别的bean(Web范围的bean)的作用域,您需要在定义bean之前进行一些初始配置。
我已按照文档中的示例将以下内容添加到我的web.xml
中:
org.springframework.web.context.request.RequestContextListener
2. 作为依赖项的作用域bean
如果您想将(例如)一个HTTP请求作用域的bean注入到另一个bean中,您必须在作用域bean的位置注入一个AOP代理。
我已经使用@Scope
注解为该bean提供了proxyMode
,如下所示:
@Controller @Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS) public class ReportBuilder implements Serializable { ... ... }
问题
尽管进行了上述配置,但我收到以下异常:
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
中有以下内容:
contextClass org.springframework.web.context.support.AnnotationConfigWebApplicationContext contextConfigLocation org.example.AppConfig org.springframework.web.context.ContextLoaderListener
并且在AppConfig.java
中有以下内容:
@Configuration @EnableAsync @EnableCaching @ComponentScan("org.example") @ImportResource("classpath:applicationContext.xml") public class AppConfig implements AsyncConfigurer { ... ... }
更新2
我已经创建了一个可复现的测试案例。这是一个更小的项目,所以有一些差异,但是发生了相同的错误。由于文件较多,我已将其上传为tar.gz
到megafileupload。
问题的出现原因是在代码设计模式中混合了不同的作用域和线程:
- 单例模式(singleton)
- 会话模式(session)或请求模式(request)
- 作业线程池(thread pool of jobs)
单例模式在任何地方都可用,这是可以的。然而,会话模式或请求模式只能在附加到请求的线程中使用,而异步作业可以在请求或会话不存在的情况下运行,因此无法使用依赖于请求或会话的bean。此外,无法确定在单独的线程中运行作业时,原始请求是哪个线程(这意味着在这种情况下aop:proxy无济于事)。
解决方法是:
- 尝试简化代码,不再使用ReportBuilder。
- 使用org.springframework.web.context.request.RequestContextListener
而不是RequestContextListener
,因为你没有使用Dispatcher Servlet。
- 如果你的问题是在使用OAuth2RestTemplate
时出现的,尝试将其作用域更改为原型(prototype)。
以上是关于(Scope 'session' is not active for the current thread; IllegalStateException: No thread-bound request found)问题的原因和解决方法的整理。
问题的原因是在当前线程中没有活动的会话(session),导致了 IllegalStateException 异常。解决方法是在web.xml中添加一个监听器(RequestContextListener),在会话组件中设置session的作用域为session,并在pom.xml中添加cglib依赖。
具体的解决步骤如下:
1. 在web.xml文件中添加以下代码:
org.springframework.web.context.request.RequestContextListener
2. 在会话组件中添加以下代码,将session的作用域设置为session:
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
3. 在pom.xml文件中添加以下代码,添加cglib依赖:
cglib cglib 3.1
另外,也可以使用ScopedProxyMode.INTERFACE而不需要cglib依赖。在这种情况下,需要一个接口。
以上方法解决了该问题,同时也提到了在Spring框架版本3.2以后,不再需要添加CGLIB的显式依赖。可以在此链接中获取更多详细信息:docs.spring.io/spring/docs/3.2.x/spring-framework-reference/…
问题原因:这个问题的原因是使用了多线程。请求对象在这些线程中不可用。
解决方法1:可以将请求对象提供给其他线程,但这会对系统施加一些限制,可能在所有项目中都无法工作。可以使用SimpleAsyncTaskExecutor
代替WorkManagerTaskExecutor
/ThreadPoolExecutorFactoryBean
来解决这个问题,并且使用RequestContextFilter
代替RequestContextListener
。在RequestContextFilter
中设置threadContextInheritable
属性,允许子线程继承父线程的上下文。
解决方法2:另一个选择是在请求线程中使用会话作用域的bean。但在某些情况下,这可能不可行,例如控制器方法使用了@Transactional
注解,或者控制器方法启动了使用线程执行并行作业步骤的批处理作业。
如果以上解决方法都不起作用,可以查看这个链接:medium.com/_maniar/...