Я добавляю всю кухонную раковину в небольшое веб-приложение, которое я разрабатываю в рамках этого поста — Spring Boot, Spring Integration, RabbitMQ и, наконец, тему поста, поддержку Websocket в Spring MVC с Spring 4.
Приложение для составления списка землетрясений в режиме реального времени
Окончательное приложение будет перечислять случаи землетрясений по всему миру и будет обновляться в режиме реального времени (если минута может считаться достаточной в реальном времени), по следующим направлениям:
Хранение информации о землетрясении
Первая часть приложения каждую минуту опрашивает данные из программы USGS Earthquake опасность, и хранит их. Я решил сохранить его непосредственно в теме RabbitMQ , которая позже будет использоваться для интеграции Websockets. Spring Integration отлично подходит для требований такой функции — используя только конфигурацию, я могу опросить службу USGS, предоставив json-канал этой информации, и записать ее в тему RabbitMQ. Вот как выглядит этот поток:
и исходный полный поток интеграции Spring для того же самого является следующим, единственный код, пропущенный здесь, является конфигурацией для rabbitmq, который является частью другого файла конфигурации:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
< import resource = "rabbit-context.xml" /> < int:inbound-channel-adapter channel = "quakeinfotrigger" expression = "''" > < int:poller fixed-delay = "60000" ></ int:poller > </ int:inbound-channel-adapter > < int:channel id = "quakeinfo" /> < int:channel id = "quakeinfotrigger" ></ int:channel > < int-http:outbound-gateway id = "quakerHttpGateway" request-channel = "quakeinfotrigger" http-method = "GET" expected-response-type = "java.lang.String" charset = "UTF-8" reply-channel = "quakeinfo" > </ int-http:outbound-gateway > < int-amqp:outbound-channel-adapter amqp-template = "amqpTemplate" channel = "quakeinfo" /> |
Итак, теперь у меня есть поток, который собирает информацию о землетрясении и сохраняет ее в теме RabbitMQ под названием «amq.topic» и внутренне подключает ключ маршрутизации «quakes.all» к каждому информационному сообщению о землетрясении, следующий шаг это выяснить, как динамически отображать эту информацию в приложении браузера.
Представление информации о Quake
Spring Framework 4.0+ упрощает разработку веб-части приложения с поддержкой обмена сообщениями на основе Websocket, которая теперь встроена в среду. Spring 4.0 использует STOMP в качестве протокола более высокого уровня для необработанных веб-сокетов — я включил ссылки, которые обеспечивают гораздо большую ясность в деталях поддержки веб-сокетов.
По сути, Spring будет выступать в качестве посредника для браузера, чтобы подписаться на тему землетрясений RabbitMQ и отображать информацию в реальном времени по мере поступления новой информации о землетрясениях, эта схема из ссылок хорошо подводит итог:
Для поддержки Spring 4 Websockets с внешним брокером требуется, чтобы брокер поддерживал протокол STOMP, что легко сделать с помощью RabbitMQ . С поддержкой STOMP в RabbitMQ конфигурация Spring MVC выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableStompBrokerRelay( "/topic/" ); config.setApplicationDestinationPrefixes( "/app" ); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint( "/quakesep" ).withSockJS(); } } |
- «/ Topic» регистрируется в качестве конечной точки, где Spring выступает в качестве шлюза для поддержки RabbitMQ STOMP
- «/ App» — это префикс приложения, в котором Spring MVC будет прослушивать запросы браузера, закодированные в фрейме сообщения STOMP, в данном конкретном случае я не получаю никаких запросов от пользовательского интерфейса, поэтому эта конечная точка на самом деле не используется
- «/ Quakesep» является конечной точкой websocket
Это все, что требуется на стороне сервера!
Теперь, чтобы клиент подписался на сообщение в теме RabbitMQ, я реализовал его в соответствии с примером в одной из справочных статей. В примере используется клиент sockjs , библиотека javascript для эмуляции websocket в браузерах.
Вот как выглядит код JavaScript для подключения к конечной точке websocket «/ quakesep» и подписки на конечную точку «/topic/quakes.all». Это внутренне регистрирует временную очередь в RabbitMQ для этого сеанса веб-сокета и отображает ключ маршрутизации AMQP «quakes.all» в эту временную очередь, по сути отправляя все сообщения о землетрясениях во временную очередь для сеанса.
01
02
03
04
05
06
07
08
09
10
|
function connect() { var socket = new SockJS( '/quakesep' ); stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { console.log( 'Connected: ' + frame); stompClient.subscribe( '/topic/quakes.all' , function(message){ showQuakeInfo(message.body); }); }); } |
вышеприведенная функция showQuakeInfo просто отображает свежую информацию о землетрясениях, когда она доступна из RabbitMQ.
Весь пример был собран вместе с Spring Boot , это обеспечило сохранение минимальных зависимостей, объявленных в pom-файле, количество настроек для запуска приложения на удивление мало — по сути, код WebSocketConfig, который я отображал выше!
- У меня есть код, доступный здесь, в GitHub
Ресурсы
- Архитектура веб-сокетов в Spring Framework
- Вебинар по созданию приложений на основе Websocket с использованием Spring Framework