2016-02-14 19 views
2

我正嘗試使用sprint啓動和spring消息創建websocket應用程序。然而,當我嘗試調用裏面我們的服務類中的一個函數,我得到了以下異常:Scope'request'對當前線程無效 - websocket版本

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] 

上做一些閱讀後,它變成了我需要做這項服務(豆)作用域豆,所以我這樣做:

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

在我的bean類,並在我的控制器我這樣做:

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

做這些改變,異常更改爲以下後:

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 

這裏是我的配置類:

@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(); 
} 

}

我的代碼主要是基於樣本代碼與春天開機運行的WebSockets,除了這一部分:

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

我在那裏得到的通知,幫助讚賞

下面的代碼的精簡版 http://www.4shared.com/file/BinrToCqce/pushnotifications.html

+2

如果您要提供服務類的代碼,可能會有一點點清楚。 –

+0

這會有點困難,但我會盡力至少寫一個虛擬服務,將重現問題 – amrnablus

+0

@KenBekov在那裏你去:http://www.4shared.com/file/BinrToCqce/pushnotifications.html 我創建了一個精簡版本,它不會拋出相同的異常,但是當您嘗試執行時,ServletRequestAttributes屬性=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); 你會得到NullPointerException,這實質上是問題的主要原因。 – amrnablus

回答

1

似乎是消息代理都有自己的線程。所以Message broker和DispathcherServlet可以在不同的線程中工作。但是你不能從另一個線程使用HttpServletRequest。因爲,當異步作業嘗試處理HttpServletRequest時,可能請求(或會話)不是實際的或不再存在。這意味着,您不能在DispatcherServlet的線程之外使用請求範圍的bean以及會話範圍的bean。

因爲您不能直接從另一個線程訪問請求或會話數據,您必須手動傳遞此數據。

+0

它已經被添加到「DispatcherServletInitializer.java」裏面 – amrnablus

+0

yah有點想通了,我猜我唯一的選擇是傳遞我需要的任何會話信息以及websocket請求並基於此進行身份驗證。 – amrnablus

+1

轉過來。主要的是,你不能直接從另一個線程訪問請求或會話數據。所以你必須手動傳遞這些數據。 感謝您的問題,我學會了自己。 ) –