3
votes

I have method in a Spring component which receives messages from a Spring Integration channel. When a message is received, it is sent to a WebSocket endpoint. This doesn't work. The message is not broadcast.

this.messagingTemplate.convertAndSend("/topic/update", dto);

However when I put the same code inside a Web Controller and put a RequestMapping on it, and call that endpoint, it works. The message is broadcast.

What might be causing it not to work, when it is called by the Spring integration executor?

when it works: .14:01:19.939 [http-nio-8080-exec-4] DEBUG o.s.m.s.b.SimpleBrokerMessageHandler - Processing MESSAGE destination=/topic/update session=null payload={XXX} .14:01:19.939 [http-nio-8080-exec-4] DEBUG o.s.m.s.b.SimpleBrokerMessageHandler - Broadcasting to 1 sessions.

when it doesnt work, second message is not there. (thread is taskExecutor-1 instead of http-nio..)

Controller code:

@RequestMapping("/testreq")
public void updateDelta() {
    SummaryDTO dto = new SummaryDTO();
    dto.setValue(-5000.0);
    dto.setName("G");

    this.messagingTemplate.convertAndSend("/topic/update", dto);

}

//this method is called by Spring Integration
//created by serviceActivator = new 
//ServiceActivatingHandler(webcontroller,"update");
public void updateDelta(SummaryDTO dto) {       
  this.messagingTemplate.convertAndSend("/topic/update", dto);

 }

message send:

synchronized(this){
...

this.updatedcontrollerchannel.send(MessageBuilder.withPayload(summarydto).build( )); }

channel creation:

updatedchannel = new DirectChannel();
updatedchannel.setBeanName("updatedcontroller");

serviceActivator = new ServiceActivatingHandler(detailService,"update");
handlerlist.add(serviceActivator);
updatedchannel.subscribe(serviceActivator);
beanFactory.registerSingleton("updatedcontroller", channel);

UPDATE I added spring messaging source code to my environment and realized the following: There are 2 instances of the SimpleBrokerMessageHandler class in the runtime. For the working copy subscriptionregistry has one entry and for the nonworking one, it has 0 subscriptions. Does this give a clue for the root cause of the problem? There is only one MessageSendingOperations variable defined and it is on the controller.

2

2 Answers

2
votes

i found the cause of the problem. Class which has @EnableWebSocketMessageBroker annotation was loaded twice and it caused two instances of SimpleBrokerMessageHandler to be created. @Artem Bilan: thanks for your time.

1
votes

Should be the problem with the non-properly injected SimpMessageSendingOperations.

This one is populated by the AbstractMessageBrokerConfiguration.brokerMessagingTemplate() @Bean.

However I would like to suggest you to take a look into the WebSocketOutboundMessageHandler from Spring Integration: https://docs.spring.io/spring-integration/docs/4.3.12.RELEASE/reference/html/web-sockets.html

UPDATE

This works for me in the test-case:

@Bean
@InboundChannelAdapter(channel = "nullChannel", poller = @Poller(fixedDelay = "1000"))
public Supplier<?> webSocketPublisher(SimpMessagingTemplate brokerMessagingTemplate) {
    return () -> {
        brokerMessagingTemplate.convertAndSend("/topic/foo", "foo");
        return "foo";
    };
}

And I have this DEBUG logs:

12:57:27.606 DEBUG [task-scheduler-1][org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler] Processing MESSAGE destination=/topic/foo session=null payload=foo
12:57:27.897 DEBUG [clientInboundChannel-2][org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler] Processing SUBSCRIBE /topic/foo id=subs1 session=941a940bf07c47a1ac786c1adfdb6299
12:57:40.797 DEBUG [task-scheduler-1][org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler] Processing MESSAGE destination=/topic/foo session=null payload=foo
12:57:40.798 DEBUG [task-scheduler-1][org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler] Broadcasting to 1 sessions.

Everything works well from Spring Integration.

That's why I asked your whole Spring Boot app to play from our side.

UPDATE 2

When you develop Web application be sure to merge all the configs contexts to a single one application context - WebApplicationContext:

If an application context hierarchy is not required, applications may return all configuration via getRootConfigClasses() and null from getServletConfigClasses().

See more info in the Spring Framework Reference Manual.