Scope 'session' is not active for the current thread; IllegalStateException: No thread-bound request found

SpringWicket

Spring Problem Overview


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. Initial web configuration

> 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.

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. Scoped beans as dependencies

> 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.

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 {
    ...
    ...
}

Problem

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

>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.

Update 1

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>

And the following in AppConfig.java:

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

Update 2

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.

Spring Solutions


Solution 1 - Spring

The problem is not in your Spring annotations but your design pattern. You mix together different scopes and threads:

  • singleton
  • session (or request)
  • thread pool of jobs

The singleton is available anywhere, it is ok. However session/request scope is not available outside a thread that is attached to a request.

Asynchronous job can run even the request or session doesn't exist anymore, so it is not possible to use a request/session dependent bean. Also there is no way to know, if your are running a job in a separate thread, which thread is the originator request (it means aop:proxy is not helpful in this case).


I think your code looks like that you want to make a contract between ReportController, ReportBuilder, UselessTask and ReportPage. Is there a way to use just a simple class (POJO) to store data from UselessTask and read it in ReportController or ReportPage and do not use ReportBuilder anymore?

Solution 2 - Spring

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.

Cause

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:

> 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.

Solution 1

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 https://stackoverflow.com/questions/7638003/accessing-request-scoped-beans-in-a-multi-threaded-web-application:

> 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.

Solution 2

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

  1. The controller method is annotated with @Async;
  2. The controller method starts a batch job which uses threads for parallel job steps.

Solution 3 - Spring

If anyone else stuck on same point, following solved my problem.

In web.xml

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

In Session component

@Component
@Scope(value = "session",  proxyMode = ScopedProxyMode.TARGET_CLASS)

In pom.xml

    <dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>3.1</version>
	</dependency>

Solution 4 - Spring

> I fixed this issue by adding following code in my file.

@Component
@Scope(value = "session",  proxyMode = ScopedProxyMode.TARGET_CLASS)

XML configuration -

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

Above we can do using Java configuration -

@Configuration
@WebListener
public class MyRequestContextListener extends RequestContextListener {
}

https://stackoverflow.com/questions/38202621/how-to-add-a-requestcontextlistener-with-no-xml-configuration

I am using spring version 5.1.4.RELEASE and no need to add below changes in pom.

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.2.10</version>
</dependency>

Solution 5 - Spring

As per documentation:

> If you are accessing scoped beans within Spring Web MVC, i.e. within a request that is processed by the Spring DispatcherServlet, or DispatcherPortlet, then no special setup is necessary: DispatcherServlet and DispatcherPortlet already expose all relevant state.

If you are runnning outside of Spring MVC ( Not processed by DispatchServlet) you have to use the RequestContextListener Not just ContextLoaderListener .

Add the following in your web.xml

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

That will provide session to Spring in order to maintain the beans in that scope

Update : As per other answers , the @Controller only sensible when you are with in Spring MVC Context, So the @Controller is not serving actual purpose in your code. Still you can inject your beans into any where with session scope / request scope ( you don't need Spring MVC / Controller to just inject beans in particular scope) .

Update : RequestContextListener exposes the request to the current Thread only.
You have autowired ReportBuilder in two places

1. ReportPage - You can see Spring injected the Report builder properly here, because we are still in Same web Thread. i did changed the order of your code to make sure the ReportBuilder injected in ReportPage like this.

log.info("ReportBuilder name: {}", reportBuilder.getName());
reportController.getReportData();

i knew the log should go after as per your logic , just for debug purpose i added .


2. UselessTasklet - We got exception , here because this is different thread created by Spring Batch , where the Request is not exposed by RequestContextListener.


You should have different logic to create and inject ReportBuilder instance to Spring Batch ( May Spring Batch Parameters and using Future<ReportBuilder> you can return for future reference)

Solution 6 - Spring

https://stackoverflow.com/a/30640097/2569475

For This Issue check My answer at above given url

Using a request scoped bean outside of an actual web request

Solution 7 - Spring

My answer refers to a special case of the general problem the OP describes, but I'll add it just in case it helps somebody out.

When using @EnableOAuth2Sso, Spring puts an OAuth2RestTemplate on the application context, and this component happens to assume thread-bound servlet-related stuff.

My code has a scheduled async method that uses an autowired RestTemplate. This isn't running inside DispatcherServlet, but Spring was injecting the OAuth2RestTemplate, which produced the error the OP describes.

The solution was to do name-based injection. In the Java config:

@Bean
public RestTemplate pingRestTemplate() {
    return new RestTemplate();
}

and in the class that uses it:

@Autowired
@Qualifier("pingRestTemplate")
private RestTemplate restTemplate;

Now Spring injects the intended, servlet-free RestTemplate.

Solution 8 - Spring

Had the same error when I had @Order annotation on a filter class. Even thou I added the filter through the HttpSecurity chain.

Removed the @Order and it worked.

Solution 9 - Spring

You just need to define in your bean where you need a different scope than default singleton scope except prototype. For example:

<bean id="shoppingCart" 
   class="com.xxxxx.xxxx.ShoppingCartBean" scope="session">
   <aop:scoped-proxy/> 
</bean>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJonView Question on Stackoverflow
Solution 1 - SpringMartin StrejcView Answer on Stackoverflow
Solution 2 - SpringJonView Answer on Stackoverflow
Solution 3 - SpringMohitView Answer on Stackoverflow
Solution 4 - SpringNoman AkhtarView Answer on Stackoverflow
Solution 5 - SpringManiView Answer on Stackoverflow
Solution 6 - SpringDeepakView Answer on Stackoverflow
Solution 7 - Springuser41871View Answer on Stackoverflow
Solution 8 - SpringMihkel L.View Answer on Stackoverflow
Solution 9 - SpringKunwar BabuView Answer on Stackoverflow