Отправить сообщение всем клиентам через SimpMessagingTemplate в ServletContextListener

Я использую Spring framework, и у меня есть рабочий контроллер websocket, который выглядит так:

@Controller
public class GreetingController {

    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws InterruptedException {
        return new Greeting("Hello, " + message.getName() + "!");
    }
}

у меня также есть эта конфигурация:

@Configuration
@EnableWebSocketMessageBroker
public class HelloWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/hello").withSockJS();
    }
}

эта часть работает отлично! Я могу успешно отправлять и получать сообщения между двумя или более браузерами с помощью Stomp.js. Вот часть, которая не работает. Я реализовал ServletContextListener, который содержит пользовательский объект, который, для простоты, я назвал "уведомитель". Уведомитель прослушивает определенные события происходит на стороне сервера. Затем он вызывает метод "notify", который должен отправлять сведения о событии всем клиентам. Но это не работает.

@WebListener
public class MessageListener implements ServletContextListener, Notifiable {

    private Notifier notifier;

    @Autowired
    private SimpMessagingTemplate messageSender;


    public MessageListener() {
        notifier = new Notifier(this);
    }

    public void contextInitialized(ServletContextEvent contextEvent) {
        WebApplicationContextUtils
        .getRequiredWebApplicationContext(contextEvent.getServletContext())
        .getAutowireCapableBeanFactory()
        .autowireBean(this);

        notifier.start();
    }

    public void contextDestroyed(ServletContextEvent contextEvent) {
        notifier.stop();
    }

    public void notify(NotifyEvent event) {
        messageSender.convertAndSend("/topic/greetings", new Greeting("Hello, " + event.subject + "!"));
    }
}

Я не получаю исключение. The SimpMessagingTemplate был успешно введен весной, поэтому он не является нулевым. Я смог войти в весенний код и понял, что SimpleBrokerMessageHandler ' s subscriptionRegistry пуст при использовании SimpMessagingTemplate. Таким образом, это должен быть отдельный экземпляр от того, который используют контроллеры. Как может Я получаю то же самое subscriptionRegistry что используется контроллерами?

1 ответов


решение было использовать весной ApplicationListener класса вместо ServletContextListener, и специально слушать для ContextRefreshedEvent.

вот мой рабочий пример:

@Component
public class MessagingApplicationListener implements ApplicationListener<ContextRefreshedEvent>, Notifiable {
    private final NotifierFactor notifierFactory;
    private final MessageSendingOperations<String> messagingTemplate;
    private Notifier notifier;

    @Autowired
    public MessagingApplicationListener(NotifierFactor notifierFactory, MessageSendingOperations<String> messagingTemplate) {
        this.notifierFactory = notifierFactory;
        this.messagingTemplate = messagingTemplate;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (notifier == null) {
            notifier = notifierFactory.create(this);
            notifier.start();
        }
    }

    public void notify(NotifyEvent event) {
        messagingTemplate.convertAndSend("/topic/greetings", new Greeting("Hello, " + event.subject + "!"));
    }

    @PreDestroy
    private void stopNotifier() {
        if (notifier != null) {
            notifier.stop();
        }
    }
}