我开发了Spring Remoting amqp rpc应用程序。
这对于在Scope SESSION中不使用bean的方法非常有效。
对于其他方法,客户端无法使用spring会话,而我会收到此异常
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.userSession': 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.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:362) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at io.kzreactive.akwtype.akwtypeback.common.service.UserSession$$EnhancerBySpringCGLIB$$55d53e95.setUser(<generated>) ~[classes/:na]
at io.kzreactive.akwtype.akwtypeback.engine.service.AppService.login(AppService.kt:30) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.remoting.support.RemoteInvocation.invoke(RemoteInvocation.java:215) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.remoting.support.DefaultRemoteInvocationExecutor.invoke(DefaultRemoteInvocationExecutor.java:39) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at io.kzreactive.akwtype.akwtypeback.gateway.rabbitmq.SessionDefaultRemoteInvocationExecutor.invoke(RabbitMQSession.kt:48) ~[classes/:na]
at org.springframework.remoting.support.RemoteInvocationBasedExporter.invoke(RemoteInvocationBasedExporter.java:78) [spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.remoting.support.RemoteInvocationBasedExporter.invokeAndCreateResult(RemoteInvocationBasedExporter.java:114) [spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.amqp.remoting.service.AmqpInvokerServiceExporter.onMessage(AmqpInvokerServiceExporter.java:80) [spring-amqp-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1457) [spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1348) [spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1324) [spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1303) [spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:785) ~[spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:769) ~[spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:77) ~[spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1010) ~[spring-rabbit-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at java.base/java.lang.Thread.run(Thread.java:844) ~[na:na]
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-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:55) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:350) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
... 24 common frames omitted
所以我将在Rabbit mq上创建并使用一个春季会议
首先,我设法在RPC调用中传递了sessionId
在服务器上我添加一个属性
class SessionDefaultRemoteInvocationFactory : DefaultRemoteInvocationFactory() {
override fun createRemoteInvocation(methodInvocation: MethodInvocation?): RemoteInvocation {
return super.createRemoteInvocation(methodInvocation)
.apply { addAttribute("sessionId", RequestContextHolder.currentRequestAttributes().sessionId) }
}
}
在客户端上我可以阅读
class SessionDefaultRemoteInvocationExecutor : DefaultRemoteInvocationExecutor() {
override fun invoke(invocation: RemoteInvocation?, targetObject: Any?): Any {
if (invocation is RemoteInvocation) {
invocation.getAttribute("sessionId")?.let {
val sessionId = it.toString()
SecurityContextHolder.getContext().authentication = AnonymousAuthenticationToken(sessionId,
"anonymousUser", listOf(SimpleGrantedAuthority("ROLE_ANONYMOUS")))
val attr = RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes // <= ERROR here
attr.request.getSession(true)
}
}
return super.invoke(invocation, targetObject)
}
}
但我无法使用它来创建春季会议
如何在此非http上下文中创建春季会话
我试图创建一个请求上下文监听器
@Configuration
@WebListener
class MyRequestContextListener : RequestContextListener()
但有相同的错误
答案 0 :(得分:0)
目前,我绕过了春季会议,并注入了具有相同行为的bean
@Component
@Scope("singleton")
class EngineThread(var engineSession: ThreadLocal<EngineSession> = ThreadLocal()) : IEngineSession by engineSession.getOrSet( { EngineSession() })
@Component
@Profile("engine & !test")
class SessionDefaultRemoteInvocationExecutor(val engineThread: EngineThread) : DefaultRemoteInvocationExecutor() {
val engineSessionStore : MutableMap<String, EngineSession> = mutableMapOf()
override fun invoke(invocation: RemoteInvocation?, targetObject: Any?): Any {
if (invocation is RemoteInvocation) {
invocation.getAttribute(SESSION_ID)?.let {
val sessionId = it.toString()
SecurityContextHolder.getContext().authentication = AnonymousAuthenticationToken(sessionId,
"anonymousUser", listOf(SimpleGrantedAuthority("ROLE_ANONYMOUS")))
if (! engineSessionStore.contains(sessionId)) {
engineSessionStore.put(sessionId, EngineSession())
}
engineThread.engineSession.set(engineSessionStore.getValue(sessionId))
}
}
return super.invoke(invocation, targetObject)
}
}
工作已经完成,但是我对这个解决方案不太满意 (我将通过软引用添加clean…,但是所有这些工作都是重新创建会话,而不是使用spring会话)