7

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.

Tito
  • 2,234
  • 6
  • 31
  • 65

0 Answers0