WebSocket протоколунда эки түрдүү билдирүүлөр түрү бар (тексттик жана экилик), бирок алардын мазмуну аныктоо каралган эмес. Протокол кардарга жана серверге WebSocket үстүндө колдонуу үчүн субпротоколдун (т.а. жогорку деңгээлдеги билдирүүлөр алмашуунун протоколу) макулдашуу механизмин аныктайт, ал билдирүүлөрдү жөнөтүүнү, алардын форматын, ар бири билдирүү мазмунун жана башкаларды аныктайт. Субпротоколду колдонуу милдеттүү эмес, бирок кардар менен сервер ортосунда билдирүү мазмунун аныктай турган протокол макулдашылышы керек.
Кыскача сүрөттөмө
STOMP (Simple Text Oriented Messaging Protocol) протоколу башында Ruby, Python жана Perl сыяктуу сценарий тилине багытталган жана корпоративдик билдирүү брокерлерине туташуу үчүн түзүлгөн. Ал жөнөкөй, кеңири колдонулган билдирүү үлгүлөрүнүн топтому үчүн иштөө үчүн түзүлгөн. STOMP TCP жана WebSocket сыяктуу ар кандай ишенимдүү эки тараптуу агымдык тармак протоколу аркылуу колдонулушу мүмкүн. STOMP текстке багытталган протокол болсо да, билдирүүлөрдүн мазмуну тексттик же экилик формада болушу мүмкүн.
STOMP – фреймдерге негизделген протокол, фреймдери HTTP негизинде түзүлгөн. Төмөнкү листингде STOMP фрейминин түзүмү көргөзүлгөн:
COMMAND header1:value1 header2:value2 Body^@
Кардарлар SEND
же SUBSCRIBE
командаларын билдирүүлөрдү жөнөтүү же катталуу үчүн колдонушу мүмкүн, destination
башчылыгы менен, ал билдирүүнүн эмне жөнүндө экенин жана аны кимдер алышы керегин аныктайт. Бул жөнөкөй жарыялоо-катталуу механизмин түзүүгө мүмкүндүк берет, ал брокер аркылуу башка байланышкан кардарларга билдирүүлөрдү жөнөтүү үчүн колдонулушу мүмкүн же серверге белгилүү бир ишти аткаруу суранычын жөнөтүү үчүн колдонулушу мүмкүн.
Эгерде сиз Spring тарабынан камсыздандырылган STOMP протоколун колдонуңуз, анда Spring'деги WebSocket тиркемеси кардарлар үчүн STOMP брокери катары иштейт. Билдирүүлөр түз мейкиндиктеги брокерге же аннотацияланган @Controller
иштетүү ыкмаларына багытталат, ал каттамдарды көзөмөлдөйт жана жазылуучуларга билдирүү жөнөтөт. Ошондой эле Spring'ди RabbitMQ, ActiveMQ жана башка STOMP брокерлери аркылуу иштөө үчүн конфигурациялоо мүмкүн. Бул учурда, Spring брокер менен TCP байланышын орнотууну колдойт, аларга билдирүүлөрдү жөнөтөт жана алардан WebSocket кардарларына таратууну жүргүзөт. Ошентип, Spring веб-тиркемелери HTTP протоколундагы унификацияланган коопсуздук, жалпы валидация жана белгилүү программалоо моделин колдонуу менен билдирүүлөрдү иштете алат.
Төмөнкү мисал кардар менен катталганды көрсөтөт, ал баалардын котировкасын алуу үчүн, сервер тарабынан мезгилдүү түзүлө турган билдирүүлөрдү жөнөтөт (мисалы, SimpMessagingTemplate
аркылуу пландаштырылган тапшырма):
SUBSCRIBE id:sub-1 destination:/topic/price.stock.* ^@
Төмөнкү мисал кардар менен соода арызы жөнөтүүнү көрсөтөт, аны сервер @MessageMapping
аннотацияланган ыкмасы аркылуу иштете алат:
SEND destination:/queue/trade content-type:application/json content-length:44 {"action":"BUY","ticker":"MMM","shares",44}^@
Аткарылгандан кийин, сервер кардарга соода тууралуу кабар жөнөтүп, анын майда-чүйдөсүн кабарлай алат.
STOMP спецификациясында дарек баасы атайын ачык калган. Бул каалаган сап болушу мүмкүн, ал эми STOMP серверлери анын семантикасы жана алар колдогон даректердин синтаксиси толук аныктайт. Бирок абдан көп учурда даректер жол сыяктуу саптардан турат, мисалы, /topic/..
публикация-каттоо (бирден көпкө) алса, /queue/
"чекит-чекитке" (бирден бирге) билдирүүлөрдү алмашууну билдирет.
STOMP серверлери MESSAGE
командасын бардык катталуучуларга билдирүүлөрдү жөнөтүү үчүн колдоно алышат. Төмөнкү мисал сервердин кармана турган кардарга баанын котировкасында билдирүү жөнөтүүсү көрсөтүлгөн:
MESSAGE message-id:nxahklf6-1 subscription:sub-1 destination:/topic/price.stock.MMM {"ticker":"MMM","price":129.45}^@
Сервер суралбаган билдирүүлөрдү жөнөтө албайт. Серверден келген бардык билдирүүлөр кардардын белгилүү бир катталуусуна жооп болууга тийиш, жана сервердин билдирүүсүнүн subscription-id
башчылыгы кардардын катталуу id
башчылыгы менен дал келүүгө тийиш.
Мурдагы кыскача сүрөттөмө STOMP протоколунун негизги түшүнүгүн берет. Биз толугу менен спецификацияны окуп чыгууну сунуштайбыз.
Артыкчылыктары
STOMP протоколун субпротокол катары колдонуу Spring Framework жана Spring Securityге WebSocket протоколунун "чийки" веб-сокеттерин колдонгондон караганда толук программалоо моделин камсыз кылат. Ошол эле нерсе HTTP менен чийки TCPни салыштырууга да тиешелүү жана Spring MVC жана башка веб-фреймворктарга көп функциялуулукту камсыз кылууга мүмкүндүк берет. Төмөндө артыкчылыктар тизмеси келтирилген:
-
Кастомдук билдирүү алмашуу протоколун жана билдирүү форматын ойлоп табуу кажети жок.
-
STOMP кардарлары, анын ичинде Java-кардарлары, Spring Framework'те жеткиликтүү.
-
Билдирүү брокерлерин (мисалы, RabbitMQ, ActiveMQ жана башкалар) каттоо жана билдирүү таратуу үчүн колдонууга болот (милдеттүү эмес).
-
Толук контроллер иштеп чыгуу логикасын ар кандай
@Controller
экземплярында уюштуруп коюуга болот жана билдирүүлөрдү STOMP дарек башчылыгы негизинде анын үстүндө маршруттоо мүмкүн, байланышты WebSocketHandler аркылуу "чийки" WebSocket билдирүүлөрүн иштетүүнүн ордуна. -
STOMP дарек башчылыгы жана билдирүү түрлөрү негизинде Spring Security аркылуу коопсуздук камсыз кылууга болот.
STOMPти активдөө
WebSocket үстүндө STOMPти колдоо spring-messaging
жана spring-websocket
модулдарында жеткиликтүү. Бул көзкарандылыктар болгондо, WebSocket үстүндө STOMP акыркы чекитин SockJS аркылуу камсыз кылып ачууга болот, бул төмөнкү мисалда көрсөтүлгөн:
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app");
config.enableSimpleBroker("/topic", "/queue");
}
}
/portfolio
– бул HTTP протоколунун URL дареги, WebSocket (же SockJS) кардарлары WebSocket протоколу боюнча байланыш түзүү үчүн туташуусу керек.- STOMP билдирүүлөрү, дарек башчылыгы
/app
менен башталган,@MessageMapping
аңнотацияланган ыкмаларга багытталат@Controller
класстарында. - Каттоо жана таратууну ишке ашыруу үчүн ички брокер сүйлөмдү колдонобуз, жана дарек башчылыгы
/topic
же/queue
менен башталган билдирүүлөрдү брокерге багыттайбыз.
Төмөнкү мисал мурунку мисалдын XML эквиваленттүү конфигурациясын көрсөтөт:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/portfolio">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic, /queue"/>
</websocket:message-broker>
</beans>
/topic
жана
/queue
башталыш префикстери өзгөчө мааниге ээ эмес. Алар жөн гана бир нече катталуучулар жана бир керектөөчү ортосундагы "жарыялоо-катталуусу" жана "чекиттен чекитке" билдирүү алмашууну айырмалоо үчүн келишимдер. Эгерде сиз тышкы брокерди колдоно турган болсоңуз, STOMP брокерине тиешелүү дарек жана префикс колдоолорун көрүү үчүн анын барагыга караңыз.
Браузерден SockJS колдонуп туташуу үчүн, sockjs-client
колдоно аласыз. STOMP үчүн көптөгөн тиркемелер өндүрүштө көп жылдар бою колдонулуп келген жогорку функциялуу jmesnil/stomp-websocket (ушул эле ошондой stomp.js деп белгилүү) китепканасын колдонуп келишет, бирок азыр колдоого алынбайт. Азыр JSteunou/webstomp-client бул китепкананын эң активдүү колдоого алынган жана өнүктүрүлгөн мураскери болуп эсептелет. Төмөнкү мисал ошол китепканага негизделген:
var socket = new SockJS("/spring-websocket-portfolio/portfolio");
var stompClient = webstomp.over(socket);
stompClient.connect({}, function(frame) {
}
Ошондой эле, эгерде туташуу WebSocket аркылуу ишке ашырылса (SockJS жок), төмөнкү кодду колдонсоңуз болот:
var socket = new WebSocket("/spring-websocket-portfolio/portfolio");
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
}
Мурдагы мисалда stompClient
үчүн login
жана passcode
башчылыктарын көрсөтүү шарт эмес. Эгерде алар көрсөтүлгөн болсо да, алар бир тараптуу (же сервер тарабында кайра аныкталмакчы) көз жазгырулышмак. Кошумча код мисалдарын көрүү үчүн:
-
"Таяныч WebSocket колдонуу" – башталышга байланыштуу колдонмо.
-
Stock Portfolio – тиркеменин мисалы.
WebSocket сервери
Негизги WebSocket серверин конфигурациялоо үчүн, "Сервер конфигурациясы" бөлүмүн колдонууга болот. Jetty түзүмүндө, бирок, HandshakeHandler
жана WebSocketPolicy
StompEndpointRegistry
аркылуу конфигурацияланууга тийиш:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio").setHandshakeHandler(handshakeHandler());
}
@Bean
public DefaultHandshakeHandler handshakeHandler() {
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setInputBufferSize(8192);
policy.setIdleTimeout(600000);
return new DefaultHandshakeHandler(
new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy)));
}
}
Кабар агымдары
Эгерде STOMP акыркы чекиттери ачылган болсо, Spring тиркемеси STOMP брокери катары иш алып барат. Бул бөлүмдө сервер тараптагы кабарлар агымы сүрөттөлөт.
spring-messaging
модулу Spring долбоорлору үчүн кеңири колдонула турган билдирүү алмаштыруучу тиркемелерди колдоо тутумун камтыйт. Бул тутум Spring Integration долбоорунун биринчи басталган элементи катары пайда болгон, бирок Spring Framework'ке кеңири колдонуу үчүн киргизилген. Төмөндө кээ бир билдирүү алмашуу абстракцияларынын кыскача сүрөттөмөсү:
-
Message: Билдирүүнүн жөнөкөй көрсөтүлүшү, анын ичинде башчылыктар жана пайдалуу маалыматтар.
-
MessageHandler: Билдирүүнү иштетүү келишими.
-
MessageChannel: Билдирүү жөнөтүү келишими, жиберүүчүлөр менен кабыл алуучулар ортосундагы эркин өз ара аракеттенүү камсыз кылат.
-
SubscribableChannel:
MessageChannel
,MessageHandler
катталуучулар менен. -
ExecutorSubscribableChannel:
SubscribableChannel
, ал билдирүүлөрдү жеткирүү үчүнExecutor
колдонулат.
Сүрөттөөчү конфигурация (т.а. @EnableWebSocketMessageBroker
аннотациясы) жана XML аттар мейкиндиги конфигурациясы (т.а. <websocket:message-broker>
) мурунку компоненттерди билдирүүлөрдү тапшыруу аппарациянын иш агымын түзүү үчүн колдонот. Төмөнкү диаграмма орнотулган жөнөкөй брокер колдонулганда колдонула турган компоненттерди көрсөтөт:

Мурдагы диаграмма үч билдирүү каналын көрсөтөт:
-
clientInboundChannel
: WebSocket кардарларынан келген билдирүүлөрдү жөнөтүү үчүн. -
clientOutboundChannel
: Серверден WebSocket кардарларына билдирүүлөрдү жөнөтүү үчүн. -
brokerChannel
: Сервер тараптагы колдонмо кодунан билдирүүлөрдү брокерге жөнөтүү үчүн.
Төмөнкү диаграмма, эгерде тышкы брокер (мисалы, RabbitMQ) каттоо жана билдирүү таратууну башкаруу үчүн конфигурацияланганда колдонулса, колдонула турган компоненттерди көрсөтөт:

Эки диаграммадагы негизги айырма TCPнун үстүндөгү тышкы STOMP брокерине билдирүүлөрдү жөнөтүү үчүн "брокер ретрансляторун (broker relay)" колдонууга турат, жана билдирүүлөрдү брокерден жазылуучу кардарларга өткөрүү.
Эгерде WebSocket байланышы аркылуу билдирүүлөр кабыл алынса, алар STOMP фреймдерине декоддолуп, Spring'дин Message
көрүнүшүнө өзгөртүлүп жана андан ары иштетүү үчүн clientInboundChannel
жөнөтүлөт. Мисалы, дарек башчылыгы /app
менен башталган STOMP билдирүүлөр аннотацияланган контроллерлердин @MessageMapping
аннотацияланган ыкмаларына маршрутталышы мүмкүн, ал эми /topic
жана /queue
билдирүүлөр билдирүү брокерине жөнөтүлө алышы мүмкүн.
Кардардан келген STOMP билдирүүсүн иштеп чыккан @Controller
билдирүү брокерине brokerChannel
аркылуу билдирүүнү жөнөтө алат, жана брокер билдирүүнү тиешелүү катталуучуларга clientOutboundChannel
аркылуу жөнөтөт. Ошондой эле контроллер HTTP суроо-талаптарынын жообунда иштей алса, клиенттин жайгашкан жери HTTP POST аркылуу аткарыла алат, андан кийин @PostMapping
аннотацияланган ыкма катталуучулар үчүн билдирүү брокерине билдирүү жөнөтө алат.
Бул процессти жөнөкөй мисал аркылуу карап чыгалы. Серверин конфигурациялоонун дагы бир мисалын карап көрөлү:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
@Controller
public class GreetingController {
@MessageMapping("/greeting")
public String handle(String greeting) {
return "[" + getTimestamp() + ": " + greeting;
}
}
Мурдагы мисал төмөнкү агымды колдоп турат:
-
Кардар
http://localhost:8080/portfolio
дарегине туташат, жана WebSocket байланышы орнотулганда, анын үстүндө STOMP фреймдери жөнөтүлө баштайт. -
Кардар
/topic/greeting
дарегин катталуу үчүн, SUBSCRIBE фреймин жиберет. Билдирүү кабыл алынып, декоддолгондон кийин,clientInboundChannel
аркылуу жөнөтүлөт жана андан кийин билдирүү брокерине маршрутталат, ал кардардын каттоосу сактайт. -
Клиент
/app/greeting
фреймин жиберет./app
префикси анын аннотацияланган контроллерлерге багытталуусуна мүмкүндүк берет./app
префикси алып салынгандан кийин, калган/greeting
бөлүгү@MessageMapping
аннотацияланган методго дал келет,GreetingController
ичинде. -
GreetingController
тарабынан кайтарылган мааниси Spring'динMessage
көрүнүшүнө өзгөртүлөт анын устунун кайтарылган маңыздын негизинде, жана чыгуу дареги боюнча стандарттуу/topic/greeting
(кайтарылган натыйжадан алынган) башчылыгы менен брокерге жөнөтүлөт жана анын жыйынтыгы менен брокер билдирүүлөрүн иштетет. -
Брокер катталуу туура келген бардык кардарларын табат жана ар бирине
clientOutboundChannel
аркылуу MESSAGE фреймин жөнөтөт, андан кийин билдирүүлөр STOMP фреймдерине коддолот жана WebSocket протоколунун негизинде байланыш аркылуу жөнөтүлөт.
Кийинки бөлүмдө аннотацияланган ыкмалар тууралуу кеңири маалымат камтылган, аргументтер жана кайтаруу түрлөрү тууралуу маалыматтар да кирет.
Аннотацияланган контроллерлер
Тиркемелер кардарлардан келген билдирүүлөрдү иштетүү үчүн @Controller
аннотацияланган класстарды колдонсо болот. Ушул сыяктуу класстар төмөнкү темаларда сүрөттөлгөндөй, @MessageMapping
, @SubscribeMapping
жана @ExceptionHandler
аннотациялау менен ыкмаларды жарыялай алат:
-
@MessageMapping
-
@SubscribeMapping
-
@MessageExceptionHandler
@MessageMapping
Билдирүү дарегине негиздеп, маршруттоо ыкмаларын аннотациялауу үчүн @MessageMapping
колдонсо болот. Бул ыкма метод деңгээлинде жана тип деңгээлинде колдоого алынышы мүмкүн. Тип деңгээлинде жалпы чагылдырууларды билдирүүчү контроллер ыкмаларын билдирүү үчүн @MessageMapping
колдонулат.
Жарашык боюнча дарек маанилери Ant стилиндеги жол трафиктери менен окшош (мисалы: /thing*
, /thing/**
), анын ичинде шаблондук өзгөрмөлөрдү колдоо (мисалы: /thing/{id}
). Маанилерге @DestinationVariable
менен аннотацияланган метод аргументтери аркылуу кайрылууга болот. Тиркемелер ошондой эле билдирүү дарек бөлүү контролун макулдашууга өтсө болот.
Колдоого алынган метод аргументтери
Төмөнкү таблицада метод аргументтери сүрөттөлгөн:
Метод аргументи | Сүрөттөмө |
---|---|
|
Толук билдирүүгө жеткиликтүүлүктү камсыз кылат. |
|
|
|
Башчылыктарга типтелген жеткиликтүүлүктү камсыз кылат. |
|
Билдирүү мазмунуна жеткиликтүүлүктү камсыз кылат, сконфигурацияланган Бул аннотация болушу шарт эмес, себеби башка аргумент менен дал келбеген учурда бул аннотация алдын-ала камтылган. Пайдалуу жүктөм аргументтерин автоматтык текширүү үчүн |
|
Белгилүү башчылык маанисине жеткиликтүүлүктү камсыз кылат – тип өзгөртүүсүн |
|
Билдирүүдөгү бардык башчылыктарга жеткиликтүүлүктү камсыз кылат. Бул аргумент |
|
Билдирүү дарегинен шаблондук өзгөрмөлөрдү алууга жеткиликтүүлүктү камсыз кылат. Зарыл болгон учурда маанилер метод аргументинин типине жараша өзгөртүлөт. |
|
WebSocket протоколу боюнча байланышты орнотуу учурунда HTTP аркылуу кирген колдонуучуну чагылдырат. |
Кайтаруу маанилери
Жарашык боюнча, @MessageMapping
аннотацияланган методдун кайтаруучу мааниси сконфигурацияланган MessageConverter
аркылуу пайдалуу маалыматка сериализацияланат жана brokerChannel
аркылуу Message
катары жөнөтүлөт, андан кийин жазылуучуларга таратыла алат. Чыгуу билдирүүсүнүн дареги кирүүчү билдирүү дареги сыяктуу эле, бирок /topic
префикси менен.
Чыгуу билдирүүсүнүн дарегин жөндөш үчүн @SendTo
жана @SendToUser
аннотацияларын колдонсо болот. @SendTo
аннотациясы дарек же бир нече дарек максаттар үчүн колдонулат. @SendToUser
аннотациясы чыгуу билдирүүсүн кирүүчү билдирүү менен байланыштуу колдонуучуга гана багыт алуу үчүн колдонулат.
Ошондой эле, @SendTo
жана @SendToUser
аннотацияларын ошол эле методдо бир эле учурда колдонсо болот, жана экөө тең класс деңгээлинде колдоого алынат, бул учурда алар классындагы бардык методдор үчүн стандартка айланат. Бирок, эске алуу керек, @SendTo
жана @SendToUser
менен метод деңгээлинде аннотациялоо класс деңгээлиндеги кандайдыр бир аннотацияларды жокко чыгарат.
Билдирүүлөр асинхрондук түрдө иштеле алат, жана @MessageMapping
аннотацияланган метод ListenableFuture
, CompletableFuture
же CompletionStage
кайтарууга болот.
Эске алуу керек, @SendTo
жана @SendToUser
аннотациялары жөн гана ыңгайлуу чаралар болуп саналат, алар SimpMessagingTemplate
колдонуп билдирүүлөрдү жөнөтүү менен бирдей. Керек болсо, татаал сценарийлерде, @MessageMapping
менен аннотацияланган методдор түздөн-түз SimpMessagingTemplate
колдонууга кайсы бири мүмкүнчүлүк бар же бул кайтарып берүү мааниси менен кошумчаланат.
@SubscribeMapping
@SubscribeMapping
аннотациясы @MessageMapping
сыяктуу эле, бирок бир гана катталуу кабарларына чектелген. Ал @MessageMapping
менен аннотацияланган ыкма сыяктуу эле аргументтерди колдойт. Бирок кайтаруу маанисинде, билдирүү катталууга жооп үчүн түз кардарга жөнөтүлөт (жана таратуу үчүн брокерге жөнөтүлбөйт). @SendTo
же @SendToUser
аннотацияларынын кошумча берүү - бул ишти жокко чыгарат жана билдирүүлөрдү брокерге жөнөтөт.
Ал эмне үчүн зарыл? Брокер /topic
жана /queue
менен туташып, контроллер /app
менен туташса, анда барабар каттоо системалары, жана /app
дарегинде кээ бир билдирүүлөрдү жөнөтүп, контроллер катталып турган бир билдирүү жөнөтөт, брокерге каттоо бар (бир жолу "суроо-жооп" билдирүү алмашуу). Алардан айырмаланып, контроллер /app
туташкан жана /queue
дарегинде бир билдирүү жөнөтпөйт.
Ал эмне үчүн зарыл эмес? Брокер менен контроллер бүтүн максаттарга бирдей префикстер менен башталса, аларды бири-бирине билдирүүлөрдү жөнөтүү үчүн колдонбоо керек, алардын эч бири бири-бирине көз карандылыгы жок билдирүүлөрдү иштетүү, анын ичинде каттоо билдирүүлөрүн иштеп чыгуу үчүн колдонула албайт. Түшкөн билдирүүлөр параллелдүү иштетилет. Бардык билдирүүлөр бирдей убакыт ичинде сакталат жана диспетчерлери аны иштетет. Эгерде бул даярданууга, каттоо сакталганга жана каттоо үчүн автоматтык түрдө брокерге жөнөтүлгөнгө чейин барабар болушу керек болсо, кардардан кабыл алуу макулдугун сураныч керек, эгерде сервер колдоосуна учурдагы брокер колдоосун утуп алса. Мисалы, Java'дагы STOMP кардары менен алдын-ала макулдугу сактоо үчүн төмөнкү кодду колдонсо болот:
@Autowired
private TaskScheduler messageBrokerTaskScheduler;
// Инициализация учурунда…
stompClient.setTaskScheduler(this.messageBrokerTaskScheduler);
// Катталууда…
StompHeaders headers = new StompHeaders();
headers.setDestination("/topic/...");
headers.setReceipt("r1");
FrameHandler handler = ...;
stompSession.subscribe(headers, handler).addReceiptTask(receiptHeaders -> {
// Каттоо даяр...
});
Сервер тарапта brokerChannel
каналы үчүн ExecutorChannelInterceptor
каттоого алса, ал каттоо билдирүүлөрүн акыркы иштелип, иштетилгенден кийин чалып, макулдуктун afterMessageHandled
ыкмасы бар.
@MessageExceptionHandler
Колдонмо @MessageMapping
менен аннотацияланган ыкмалардан чыккан начарлоолорду иштетүү үчүн @MessageExceptionHandler
менен аннотацияланган ыкмаларды колдонушу мүмкүн. Сиз бул аннотация аркылуу же анын аргументинде деп билдирмелерди жарыяласаңыз болот, эгер экземплярына жеткиликтүүлүк үчүн талап кылынса. Төмөнкү мисалда начарлоосу анын метод аргументинде жарыяланган:
@Controller
public class MyController {
// ...
@MessageExceptionHandler
public ApplicationError handleException(MyException exception) {
// ...
return appError;
}
}
@MessageExceptionHandler
менен аннотацияланган ыкмалар метод кол тамгаларынын ийкемдүү жана @MessageMapping
аннотацияланган ыкмалар сыяктуу эле аргумент түрлөрүн жана кайтаруу маанилерин колдойт.
Мындай аннотацияланган ыкмалар, адатта, алар жарыяланган @Controller
(же класс иерархиясында) ичинде колдонулат. Эгер сизге ушундай ыкмалар глобалдуу деңгээлде (бардык контроллерлордун ичинде) колдонулуусу керек болсо, @ControllerAdvice
менен аннотацияланган класста жарыялоого болот. Бул Spring MVCтеги функциялар менен салыштырганда жеткиликтүү.
Билдирүүлөрдү жөнөтүү
Же колдонмодо кайсы бир бөлүгүнөн байланыштырылган кардарларга билдирүүлөр жөнөтүү керек болсо эмне болот? Ар бир колдонмо компоненти brokerChannel
аркылуу билдирүүлөр жөнөтө алат. Муну жасоонун эң оңой жолу – SimpMessagingTemplate
деңгээлде киргизип, аны билдирүүлөрдү жөнөтүү үчүн колдонуу. Бул адатта, тип аркылуу киргизилип, мисалда көрсөтүлгөндөй:
@Controller
public class GreetingController {
private SimpMessagingTemplate template;
@Autowired
public GreetingController(SimpMessagingTemplate template) {
this.template = template;
}
@RequestMapping(path="/greetings", method=POST)
public void greet(String greeting) {
String text = "[" + getTimestamp() + "]:" + greeting;
this.template.convertAndSend("/topic/greetings", text);
}
}
Бирок ошондой эле (проекттеги башка типтеги биндерден да бар болсо) аны аты менен аныктоо мүмкүн.
Жөнөкөй брокер
Орнотулган жөнөкөй билдирүү брокери, кардарлардан келген каттоо суранычтарын иштетип, аларды эсине сактап, туура даректер менен кардарларга билдирүүлөрдү таратып берет. Брокер ошондой эле Ant стилиндеги дарек чаптамаларын колдойт.
Эгерде тапшырма планировщикасы орнотулса, жөнөкөй брокер STOMP жүрөк согуусун колдой алат. Планировщикти жөндөө үчүн, сиздин TaskScheduler
өз биниңизди жарыялай алат жана аны MessageBrokerRegistry
аркылуу орнотууга болот. Ошондой эле, WebSocket колдоо конфигурациясындагы автоматтык түрдө жарыяланган планировщикти колдонуу мүмкүн, бирок буга @Lazy
аннотациясы керек, WebSocket'тин ички конфигурациясы менен сиздин WebSocketMessageBrokerConfigurer
ортосунда циклдик көзкарандылыктардын пайда болушунан качуу үчүн. Мисалы:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private TaskScheduler messageBrokerTaskScheduler;
@Autowired
public void setMessageBrokerTaskScheduler(@Lazy TaskScheduler taskScheduler) {
this.messageBrokerTaskScheduler = taskScheduler;
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/")
.setHeartbeatValue(new long[] {10000, 20000})
.setTaskScheduler(this.messageBrokerTaskScheduler);
// ...
}
}
Тышкы брокер
Жөнөкөй брокер башталыш үчүн жакшы, бирок ал STOMP командаларынын бир бөлүгүн гана колдойт (ал ack маанилерин, кабыл алуу макулдугун жана калган бир нече функцияларды колдобойт), жөнөкөй билдирүү жөнөтүү циклин колдонот жана кластирлөө үчүн жараксыз. Колдонмолорду толук функциялуу билдирүү брокер менен жаңыртууну караса болот.
Сиз тандаган билдирүү брокери боюнча STOMP документициясына кайрылыңыз (мисалы, RabbitMQ, ActiveMQ ж. б.), брокерди орнотуп, аны STOMP колдоосу менен ишке киргизиңиз. Андан кийин Spring конфигурациясында STOMP брокер ретрансляторун (жөнөкөй брокердин ордуна) активдештирсеңиз болот.
Төмөнкү конфигурация толук функциялык брокерди камтыйт:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue");
registry.setApplicationDestinationPrefixes("/app");
}
}
Төмөнкү мисалда мурунку мисалдын конфигурациясын XML эквиваленттүү көрсөткөн:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/portfolio" />
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:stomp-broker-relay prefix="/topic,/queue" />
</websocket:message-broker>
</beans>
Мурунку конфигурациятагы STOMP брокер ретранслятору Springден MessageHandler
катары билдирүүлөрдү иштете алат, аларды тышкы билдирүү брокерине жөнөтөт. Бул үчүн ал брокер менен TCP байланышын орнотот, маалыматын брокерге жөнөтөт, андан кийин брокерден кабыл алынган маалыматтарды кардарларга WebSocket сессиялары аркылуу жөнөтөт. Бул жагынан анда эки тараптуу байланыш бар, эки тарапта маалыматты өткөрүүчү катары иштейт.
io.projectreactor.netty:reactor-netty
жана
io.netty:netty-all
көзкарандылыктарын кошуңуз.
Кошумча, тиркемелердин компоненттери (мисалы, HTTP суроо-талаптарды иштетүүчү ыкмалар, бизнес кызмат көрсөтүүлөр ж.б.) ретрансляторго билдирүү жөнөтсө болот.
Негизги максаты, ретранслятор жогорку ишенимдүүлүктү жана масштабдуулукту камсыз кылат.
Брокер байланышы
STOMP брокер ретранслятору жалгыз "системалык" TCP байланыш менен брокерге туташа алат. Бул байланыш жалгыз иштетүүчү ыкмалардан келген системаларга арналган, бирок кабыл алуу үчүн эмес. Бул байланыш үчүн STOMP эсептик маалыматтарды жөндәө мүмкүн (б.а. STOMP башчылыктарындагы login
жана passcode
). Бул аттар мейкиндиги жана Java конфигурациясында systemLogin
жана systemPasscode
касиеттери катары көрсөтүлөт, демейки маанилери guest
жана guest
.
STOMP брокер ретранслятору ар бир байланышкан кардардын WebSocket байланышы үчүн өзүнчө TCP байланышын түзөт. Кардарлар үчүн түзүлгөн бардык TCP байланыштары үчүн STOMP эсептик маалыматтарды жөндөөгө болот. Бул аттар мейкиндиги жана Java конфигурациясында clientLogin
жана clientPasscode
касиеттери катары көрсөтүлөт, демейки маанилери guest
жана guest
.
CONNECT
кадрына
login
жана
passcode
башчылыктарын дайыма орнотот. Ошондуктан WebSocket кардарлар бул башчылыктарды белгилөөнүн кажети жок. Алар эске алынбайт. WebSocket кардарлар WebSocket акыркы чекити коопсуздугун камсыз кылуу жана кардардын ким экендигин аныктоо үчүн HTTP атын аныктоону колдонушу керек.
STOMP брокер ретранслятору "системалык" TCP байланышы аркылуу брокерге жана андан жүрөк согуу билдирүүлөрүн жөнөтөт. Жөнөтүү жана алуунун жүрөк согуу интервалдарын жөндөөгө болот (демейки боюнча 10 секунд). Брокер менен байланыш үзүлсө, брокер ретранслятору ар бир 5 секунддан ар бирин кайра байланышуу аракетин улантат.
Каалаган Spring биндери ApplicationListener<BrokerAvailabilityEvent>
интерфейсин ишке ашырып, эгерде "системалык" байланыш узулган жана башка жалгашылган кезде билдирүү алуу мүмкүн. Мисалы, баанын котировкасында маалыматтарды таратып жаткан кызмат brokerAvailabilityEventти ала алат жана билдирүүлөрдү таратууну токтото алат, эгер болсо "системалык" байланыш активдүү эмес.
Демейки боюнча STOMP брокер ретранслятору дайыма бир эле хост жана порт менен туташтырылат - жана эгерде байланыш үзүлсө кайра туташат. Бир нече даректерди туташууга аракет кылуунда айланып кетүү үчүн, белгилүү хост жана порт ордуна дарек камсыздоочуну жөндөөгө болот. Бул кантип жасаларын төмөнкү мисалда көрсөтүлгөн:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
// ...
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue/", "/topic/").setTcpClient(createTcpClient());
registry.setApplicationDestinationPrefixes("/app");
}
private ReactorNettyTcpClient<byte[]> createTcpClient() {
return new ReactorNettyTcpClient<>(
client -> client.addressSupplier(() -> ... ),
new StompReactorNettyCodec());
}
}
Такшалган STOMP брокер ретранслятору virtualHost
касиети менен да жөндөө мүмкүн. Бул касиеттин мааниси ар бир CONNECT
фрейминин host
башчылыгы катары дайындалып жана пайдаланылууда (мисалы, бул облак чөйрөдө, анда чыныгы хост, TCP байланышын түзүп жаткан хост менен айырмаланышы мүмкүн, ал облак STOMP кызмат көрсөтүүлөрүн сунуштайт).
Чекиттерди бөлүү катары колдонуу
Билдирүүлөр @MessageMapping
аннотацияланган ыкмаларга багытталганда, алар AntPathMatcher
менен салыштырылат. Демейки боюнча, шаблондордун бөлгүчү катары диагоналдык сызык (/
) колдонулат. Бул веб-тиркемелер үчүн жакшы жыйынтык, HTTP протоколунун URL даректери менен окшош. Бирок эгерде сиз билдирүү алмашуу макулдашууларына көнгөн болсоңуз, анда бөлгүч катары чекитти (.
) колдонууга өтүп кетсеңиз болот.
Төмөнкү мисалда Java конфигурациясы аркылуу муну кантип жасоо көрсөтүлгөн:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
// ...
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setPathMatcher(new AntPathMatcher("."));
registry.enableStompBrokerRelay("/queue", "/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
Төмөнкү мисалда мурунку мисалдын конфигурациясынын XML эквиваленттүү көрсөткөн:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:message-broker application-destination-prefix="/app" path-matcher="pathMatcher">
<websocket:stomp-endpoint path="/stomp"/>
<websocket:stomp-broker-relay prefix="/topic,/queue" />
</websocket:message-broker>
<bean id="pathMatcher" class="org.springframework.util.AntPathMatcher">
<constructor-arg index="0" value="."/>
</bean>
</beans>
Ошондон кийин контроллер, мисалы, төмөнкү мисалда көрсөтүлгөндөй, @MessageMapping
аннотацияланган ыкмаларга сүйлөшүү бөлгүчү катары чекитти (.
) колдонууга өтүп кетет:
@Controller
@MessageMapping("red")
public class RedController {
@MessageMapping("blue.{green}")
public void handleGreen(@DestinationVariable String green) {
// ...
}
}
Ошондо кардар /app/red.blue.green123
дарегине билдирүү жөнөтө алат.
Мурунку мисалда биз брокердин "ретранслятору" үчүн бөлгүчтөрдү өзгөртүлгөн жокпуз, анткени ал толугу менен тышкы билдирүү брокерине көз каранды. STOMP колдонууган брокерлери боюнча документацияга кайрылыңыз, ал кандай макулдашууларды колдоорун билүү үчүн.
Экинчи жагынан, "жөнөкөй брокер" коюлган PathMatcher
ге көз каранды, ошондуктан, бөлгүчтү өзгөртсөңүз, бул өзгөртүү брокерге да жана билдирүү менен байланышкан шаблондорун салыштыруусуна да тиешелүү болот.
Аутентификация
WebSocket аркылуу ар бир STOMP билдирүү алмашуу сессиясы HTTP суроо-талаптары менен башталат. Бул суроо WebSocket аркылуу туташуу (мисалы, WebSocket байланышынын орнотуусун аутентификациялоо) же SockJS аркылуу өткөрүү механизмдери үчүн HTTP суроо-талаптары болуп саналат.
Көптөгөн веб-тиркемелерде HTTP суроо-талаптарын коргоо үчүн аутентификация жана авторизация каражаттары бар. Адатта, колдонуучу Spring Security аркылуу аутентификацияланат, мисалы, кирүү экраны, негизги HTTP аутентификациясы же башка жолу аркылуу. Аутентификацияланган колдонуучу үчүн коопсуздук тутуму HTTP сессиясында сакталат жана cookie негизинде ошол эле сессиядагы келечектеги суроо-талаптарына байланыштырып жөнөтүлөт.
Ушундан улам, WebSocket байланышынын же SockJS өткөрүү механизмдерине HTTP суроо-талаптарына аутентификацияланган колдонуучу көбүнчө бар экендиги бар. Spring автоматтык түрдө бул колдонуучуну анын WebSocket же SockJS сессиясы менен байланыштырып, андан кийин STOMP аркылуу жөнөтүлгөн билдирүүлөргө пайдалануу башчылыгын кошот.
Кыскача айтканда, типтүү веб-тиркеме коопсуздукту камсыз кылуу үчүн эч нерсе кошо албашы керек. Колдонуучу HTTP деңгээлинде аутентификацияланат, анын коопсуздук контексти HTTP сессиясында cookie негизинде сакталат (ошондо WebSocket же SockJS сессиялары аутентификацияланган колдонуучу бар), андан кийин ар бир Message
менен колдонуучу башчылыгын кошумча камтыйт.
STOMP протоколу чындыгында CONNECT
ф
GO TO FULL VERSION