I have an spring boot app that is exchanging messages over binary websocket. I.e. NO STOMP, AMQP etc. or any other messaging protocol!!! Now I need to mark one of my classes with the Scope of "websocket". Like that befow:
@Service("session")
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Session {
...
}
I have read the documentation here that quote:
" WebSocket-scoped beans can be injected into controllers and any channel interceptors registered on the "clientInboundChannel". "
I would like to emphasis the word "and" in that sentence.
Well i do have a controller, but i do not have any channelInterceptor. I am injecting this as:
@Controller("entryPoint")
public class EntryPoint {
@Autowired
private ApplicationContext applicationContext;
private ApplicationEventPublisher applicationEventPublisher;
@Autowired
private Session session;
...
@PostConstruct
public void init() {
// Invoked after dependencies injected
logger.info("EntryPoint init method i.e. @PostConstruct invoked");
}
...
}
Now the first thig i found to be interesting is that i need the annotation @EnableWebSocketMessageBroker i.e. it seems that @EnableWebSocket is not enough , but then comes the question why. I should be able to define that scope independinglly whether i am using messaging protocol or not. At least that is what i belive.
anyway without it i am getting the error
java.lang.IllegalStateException: No Scope registered for scope name 'websocket'
I said ok, lets create a dummy config file for the message broker which is bringing additional dependencies such as :
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-net</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.13.Final</version>
</dependency>
as a config like
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/testEndPoint");
}
@Override
public void configureClientInboundChannel(ChannelRegistration inboundChannelRegistration) {
}
@Override
public void configureClientOutboundChannel(ChannelRegistration outboundChannelRegistration) {
}
@Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
return true;
}
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration webSocketTransportRegistration) {
webSocketTransportRegistration.setMessageSizeLimit(45678910);
webSocketTransportRegistration.setSendBufferSizeLimit(9101112);
webSocketTransportRegistration.setSendTimeLimit(123456789);
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
System.out.println("WEB SOCKET ARGUMENT RESOLVER");
}
@Override
public void addReturnValueHandlers(
List<HandlerMethodReturnValueHandler> arg0) {
System.out.println("WEB SOCKET RETURN VALUE HANDLER");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
StompBrokerRelayRegistration stompBrokerRelayRegistration = config.enableStompBrokerRelay(
"/topic/",
"/queue/errors",
"/exchange/amp.direct/testaError/",
"/exchange/amp.direct/testCreateAccount/"
);
stompBrokerRelayRegistration.setRelayHost("127.0.0.6");
stompBrokerRelayRegistration.setRelayPort(61613);
stompBrokerRelayRegistration.setSystemLogin("guest");
stompBrokerRelayRegistration.setSystemPasscode("guest");
stompBrokerRelayRegistration.setAutoStartup(true);
stompBrokerRelayRegistration.setSystemHeartbeatSendInterval(5000);
stompBrokerRelayRegistration.setSystemHeartbeatReceiveInterval(4000);
config.setApplicationDestinationPrefixes("/app");
}
}
which brings the error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.serverSyncSession': Scope 'websocket' 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 SimpAttributes found. Your code is probably not processing a client message and executing in message-handling methods invoked by the SimpAnnotationMethodMessageHandler?
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
...
Caused by: java.lang.IllegalStateException: No thread-bound SimpAttributes found. Your code is probably not processing a client message and executing in message-handling methods invoked by the SimpAnnotationMethodMessageHandler?
at org.springframework.messaging.simp.SimpAttributesContextHolder.currentAttributes(SimpAttributesContextHolder.java:82) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.messaging.simp.SimpSessionScope.get(SimpSessionScope.java:36) ~[spring-messaging-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
... 45 common frames omitted
While the message is clear i.e. my code is indeed not thread bound and is executed in a messageHandelr just not in the SimpAnnotationMethodMessageHandler, but in a BinaryMessageHandler class that extends BinaryWebSocketHandler. Why should i not be able to place a scope on a bean it is clearlly used by the websockets. Why do we need all annotation @EnableWebSocketMessageBroker at all and all following dependencies?
It is not really clear to me what else do i need to do in order to get my bean with the right scope. Somehow i have the feeling that this will get me again to some messaging dependency that i am really trying to avoid.
My question is does anyone have some hint for me what do I need to do in BinaryMessageHandler in order to tell spring to thread that session bean with the scope "wesocket". Is there a way to achive that without the annotation @EnableWebSocketMessageBroker?
any feedback is appreciated.