java - servidor - Enviar mensaje a todos los clientes a través de SimpMessagingTemplate en ServletContextListener
socket java ejemplo (1)
La solución fue utilizar la clase ApplicationListener
de Spring en lugar de ServletContextListener
, y escuchar específicamente ContextRefreshedEvent
.
Este es mi ejemplo de trabajo:
@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();
}
}
}
Estoy usando el framework Spring y tengo un controlador websocket que funciona así:
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws InterruptedException {
return new Greeting("Hello, " + message.getName() + "!");
}
}
También tengo esta configuración:
@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();
}
}
Esa parte funciona muy bien! Puedo enviar y recibir mensajes con éxito entre dos o más navegadores usando Stomp.js. Aquí está la parte que no funciona. He implementado un ServletContextListener
que contiene un objeto personalizado que, por simplicidad, he llamado ''notificador''. El notificador escucha que ocurran ciertos eventos en el lado del servidor. Luego llama al método ''notify'', que se supone que envía detalles sobre el evento a todos los clientes. Sin embargo, no funciona.
@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 + "!"));
}
}
No tengo una excepción SimpMessagingTemplate
ha sido inyectado con éxito por Spring, por lo que no es nulo. He podido entrar en el código de Spring y he descubierto que el SimpleBrokerMessageHandler
de SimpleBrokerMessageHandler
está vacío cuando se utiliza SimpMessagingTemplate
. Por lo tanto, debe ser una instancia diferente de la que usan los controladores. ¿Cómo puedo obtener el mismo subscriptionRegistry
que utilizan los controladores?