Search code examples
javaspringspring-bootspring-websocket

Scope 'request' is not active for the current thread - websocket edition


I'm trying to create a websocket app using sprint boot and spring messaging. However, when i try to call a function inside one of our service classes, i got the following exception:

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.
    at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at com.propspace.intl.psauth.service.PsSessionHandler.getCurrentRequest(PsSessionHandler.java:83) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.psauth.service.PsTokenService.getTokenValue(PsTokenService.java:167) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.psauth.service.PsTokenService.getCurrentToken(PsTokenService.java:66) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.psauth.service.AuthPersistenceService.getCurrentUser(AuthPersistenceService.java:124) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.psauth.service.AuthPersistenceService$$FastClassBySpringCGLIB$$b662e141.invoke(<generated>) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:121) ~[spring-retry-1.1.1.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at com.propspace.intl.psauth.service.AuthPersistenceService$$EnhancerBySpringCGLIB$$d5176572.getCurrentUser(<generated>) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.psauth.service.AuthorizationService.getCurrentLoggedInUser(AuthorizationService.java:115) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.common.service.PsNotificationHandler.refindUserId(PsNotificationHandler.java:196) ~[propspace-common-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.common.service.PsNotificationHandler.getAllNotificationsOfUser(PsNotificationHandler.java:68) ~[propspace-common-0.1.6-SNAPSHOT.jar:na]
    at com.propspace.intl.pushnotifications.controller.NotificationController.greeting(NotificationController.java:47) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:198) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:497) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:87) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]

After doing some reading on it, it turned out i needed to make this service (bean) a scoped bean, so i did this:

@Scope(value= "request", proxyMode=org.springframework.context.annotation.ScopedProxyMode.TARGET_CLASS)

On my bean class, and in my controller i did this:

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

After doing those changes, the exception changes to the following:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.notificationController': 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: 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.
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.getTarget(CglibAopProxy.java:685) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:636) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at com.propspace.intl.pushnotifications.controller.NotificationController$$EnhancerBySpringCGLIB$$d92fa60c.greeting(<generated>) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:198) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:497) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:87) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]
Caused by: 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.
    at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    ... 20 common frames omitted

Here's my config class:

@Configuration

@EnableWebSocketMessageBroker
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    config.setApplicationDestinationPrefixes("/app");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/hello").withSockJS();
}

@Bean()
public NotificationHandler notificationHandler( ) {
    return new PsNotificationHandler();
}

@Bean
@ConditionalOnMissingBean
public RequestContextFilter requestContextFilter() {
    RequestContextFilter rcf = new RequestContextFilter();
    rcf.setThreadContextInheritable(true);
    return rcf;
}

@Bean
@ConditionalOnMissingBean
public RequestContextListener RequestContextListener() {
    return new RequestContextListener();
}

@Bean
public HttpSessionIdHandshakeInterceptor httpSessionIdHandshakeInterceptor() {
    return new HttpSessionIdHandshakeInterceptor();
}

}

My code is mostly based on a sample code for running websockets with spring boot, except for this part:

Object nots = notificationHandler.getAllNotificationsOfUser(null, false, false);

where i'm getting the notifications, help appreciated

Here's a stripped down version of the code http://www.4shared.com/file/BinrToCqce/pushnotifications.html


Solution

  • Seems to be Message broker has its own thread. So Message broker and DispathcherServlet work in different threads. But you can't use HttpServletRequest from another thread. Because, when asynchronous job will try to process HttpServletRequest, there is possibility that request(or session) is not actual or does not exist anymore. This is means, that you can't use request scoped beans as well as session scoped beans outside of DispatcherServlet's thread.

    Since, you can't access request or session data directly from another thread you have to pass this data manually.