WebSocket protokoli ikki xil xabarlarni (matnli va ikkilik) aniqlaydi, lekin ularning mazmuni belgilanmagan. Protokol mijoz va serverga o'z xabar almashish protokoli (ya'ni, yuqoriroq darajadagi xabar almashish protokoli) ishlatish mexanizmini kelishib olish imkonini beradi, bu esa WebSocket ustida mijoz va server o'zaro qaysi xabarlarni jo'natishi mumkinligini, ularning formati, xabarlarning mazmuni va hokazolarni aniqlaydi. Mijoz va server o'rtasida qandaydir mazmunli protokol kelishib olinishi kerak.
Qisqacha tavsif
STOMP (Simple Text Oriented Messaging Protocol) dastlab ssenariy tillari uchun yaratilgan (masalan, Ruby, Python va Perl) korporativ xabar brokerlariga ulanish uchun. Bu odatda ishlatiladigan oddiy xabar almashish shablonlarining kichik qismi bilan ishlash uchun mo'ljallangan. STOMP har qanday ishonchli ikki yo'nalishli stream tarmoq protokoli, masalan TCP va WebSocket orqali ishlatilishi mumkin. STOMP matn bilan yo'naltirilgan protokol bo'lsa-da, xabarlarning foydali ma'lumotlari ham matn, ham ikkilik shaklda bo'lishi mumkin.
STOMP — bu HTTP asosida tuzilgan kadrlar asosidagi protokol. Quyidagi ro'yxat STOMP kadrining tuzilishini ko'rsatadi:
COMMAND header1:value1 header2:value2 Body^@
Mijozlar SEND yoki SUBSCRIBE buyruqlaridan foydalangan holda xabarlarni jo'natish yoki ularga obuna bo'lishi mumkin, bu xabar nima haqida va kim uni olishi kerakligini ifodalovchi destination sarlavhasini qo'shib. Bu broker orqali boshqa mijozlarga xabar jo'natish yoki serverdan ma'lum bir ishni bajarishni so'rash uchun xabar yuborish uchun oddiy nashr-obuna mexanizmini yaratishga imkon beradi.
Agar siz Spring'dan STOMP protokolni qo'llab-quvvatlaydigan vositalardan foydalansangiz, Spring'dagi WebSocket ilovasi mijozlar uchun STOMP brokeri sifatida ishlaydi. Xabarlar @Controller annotatsiyasi bilan belgilangan xabarlarni qayta ishlash usullariga yoki obunalarni kuzatadigan va xabarlarni obunachilarga tarqatadigan oddiy xotira brokeriga yuboriladi. Bundan tashqari, Splekt brokerlar bilan ishlash uchun Spring'ni sozlash mumkin (masalan, RabbitMQ, ActiveMQ va boshqalar) haqiqiy xabarlarni tarqatish uchun. Bunday hollarda Spring broker bilan TCP aloqalarini qo'llab-quvvatlaydi, unga xabarlarni uzatadi va u orqali xabarlarni ulanish WebSocket mijozlariga uzatadi. Shu tarzda, Spring veb-ilovalari HTTP protokoli asosida yagona xavfsizlik, umumiy tasdiqlash va xabarlarni qayta ishlash uchun tanish dasturlash modelidan foydalanishi mumkin.
Quyidagi misolda, server rejalashtirilgan vazifa orqali (SimpMessagingTemplate) periodik jo'natilishi mumkin bo'lgan aktsiyalar kotirovkalari uchun obuna bo'lgan mijoz namoyish etilgan:
SUBSCRIBE id:sub-1 destination:/topic/price.stock.* ^@
Keyingi misolda, server @MessageMapping annotatsiyasi bilan belgilangan usul yordamida qayta ishlashi mumkin bo'lgan savdo so'rovini jo'natadigan mijoz namoyish etilgan:
SEND
destination:/queue/trade
content-type:application/json
content-length:44
{"action":"BUY","ticker":"MMM","shares",44}^@
Bajarilgandan so'ng, server mijozga savdo tasdiqlash va batafsil ma'lumotlarni yuborishi mumkin.
Maqsad manzilining qiymati STOMP spetsifikatsiyasida ataylab noaniq qoldirilgan. Bu har qanday satr bo'lishi mumkin va STOMP serverlari qo'llab-quvvatlaydigan manzil maqsadlarining semantika va sintaksisini to'liq aniqlaydi. Biroq, ko'p hollarda manzil maqsadlari yo'llarga o'xshash satrlar sifatida ko'rsatiladi, bu erda /topic/.. nashrga-obuna (bir ko'pchilikka), /queue/ nuqtadan-nuqtaga (bitta-bitta) xabar almashishni anglatadi.
STOMP serverlari hamma obunachilarga xabarlar tarqatish uchun MESSAGE buyruqdan foydalanishi mumkin. Keyingi misolda, server obunachiga aktsiyalar kotirovkasini jo'natmoqda:
MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM
{"ticker":"MMM","price":129.45}^@
Server so'ralmagan xabarlar jo'natolmaydi. Serverdan barcha xabarlar mijozning aniq obunasiga javob bo'lishi kerak va server xabaridagi subscription-id sarlavhasi mijozning obuna id sarlavhasi bilan mos kelishi kerak.
Avval aytilgan qisqacha tavsif STOMP protokolining eng asosiy tushunchasini taqdim etishga mo'ljallangan. Biz sizga STOMP protokolining spetsifikatsiyasi bilan to'liq tanishib chiqishni tavsiya qilamiz.
Foydali tomonlari
STOMP dasturlash modeli Spring Framework va Spring Security tomonidan WebSocket protokolidagi faqat oddiy web-socketsdan ko'ra boyroq funksiyalarni taqdim etish imkonini beradi. Bu HTTP va oddiy TCP larni taqqoslashni eslatadi va Spring MVC va boshqa web freymvorklar qanday boy funksiyalarni taqdim etishini ko'rsatadi. Quyida ko'rsatib o'tilganlar:
-
Maxsus xabarlar almashinuvi protokolini va xabarlarni formatlash o'ylab topishning hojati yo'q.
-
STOMP mijozlari, Jumladan Java-mijozlari Spring Framework'da mavjud.
-
(Ixtiyoriy) xabarlar brokerlari (masalan, RabbitMQ, ActiveMQ va boshqalar) dan foydalanib obunalar va tarqatishni boshqarish mumkin.
-
Ilova logikasini bir yoki ko'proq
@Controllernusxalarida tashkil etish mumkin va xabarlar destination sarlavhalari asosida ularga yo'naltirilishi mumkin, oddiy WebSocket xabarlarini bittaWebSocketHandlerbilan qayta ishlash o'rniga. -
Spring Security STOMP maqsad manzillari va xabar turlari asosida xabarlarni himoya qilish uchun ishlatilishi mumkin.
STOMP faollashtirish
WebSocket ustida STOMP ni qo'llab-quvvatlash spring-messaging va spring-websocket modullarida mavjud. Har ikkisi zanjirda Toplam bilan STOMP ustiga WebSocket joyidan foydalanib bo'ladi, bu orqali SockJS-da zaxira variant tushib tushganida, quyida namoyish etilgan misolda ko'rsatilgan:
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 protokoli manzili bu WebSocket (yoki SockJS) mijozlari WebSocket aloqasini tasdiqlash uchun ulanishi kerak bo'lgan nuqta.- STOMP xabarlarida, destination sarlavhalari
/appbilan boshlanadiganlar@MessageMappingbilan belgilangan metodlarga,@Controllerannotatsiyasi bilan belgilangan sinflarda yo'naltiriladi. - Obunalar va tarqatish uchun ichki xabarlar brokeridan foydalanib, xabarlarni, sarlavhalari
/topic `yoki `/queuebilan boshlanadiganlarni brokerga yo'naltiramiz.
Quyidagi misol oldingi misoldan XML konfiguratsiya ekvivalentini ko'rsatadi:
<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 va
/queue prefikslarining o'ziga xos ahamiyati yo'q. Ular "nashriyot-obuna" va "nuqtadan-nuqtaga" xabar almashishni farqlash uchun shartnoma sifatida xizmati qilishi mumkin (ya'ni ko'plab mijozlar va yakka-yakka iste'molchi o'rtasida). Agar siz tashqi brokerdan foydalansangiz, STOMP broker manzillari va prefikslari bilan qanday ishlashni bilish uchun STOMP broker sahifasiga murojaat qiling.
SockJS-dan foydalangan holda brauzer orqali ulanish uchun sockjs-client dan foydalanishingiz mumkin. STOMP bilan ko'plab dasturlar jmesnil/stomp-websocket (stomp.js nomi bilan ham tanilgan) kutubxonasidan foydalangan, u uzun yillar davomida ishlatilgan va ishlab chiqarishda ishlatilgan, ammo endi qo'llab-quvvatlanmaydi. Hozirda JSteunou/webstomp-client bu kutubxonaning eng faol rivojlanib borayotgan va qo'llab-quvvatlanayotgan vorisi hisoblanadi. Quyidagi kod namoyishi unga asoslangan:
var socket = new SockJS("/spring-websocket-portfolio/portfolio");
var stompClient = webstomp.over(socket);
stompClient.connect({}, function(frame) {
}
Bundan tashqari, aloqani WebSocket orqali (SockJS siz) amalga oshirishda, quyidagi koddan foydalanishingiz mumkin:
var socket = new WebSocket("/spring-websocket-portfolio/portfolio");
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
}
Oldin misolda, stompClient uchun login va passcode sarlavhalarini ko'rsatish shart emas. Agar bu amalga oshirilgan bo'lsa, ham ular server orqali e'tiborsiz qilingan bo'lardi (yoki aksincha, o'zgartirilgan bo'lardi). Qo'shimcha kod misollarini quyida ko'ring:
-
"WebSocketdan foydalanib interaktiv veb dasturlash" orqali boshlash uchun qo'llanma.
-
Aksiya portfeli misol ilova.
WebSocket serveri
Asosiy WebSocket serverini sozlash uchun "Server konfiguratsiyasi" bo'limidagi ma'lumotlar qo'llanilishi mumkin. Jetty holatida esa HandshakeHandler va WebSocketPolicy ni StompEndpointRegistry orqali o'rnatish kerak:
@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)));
}
}
Xabarlar oqimi
STOMP nuqtasi ochilgan holatda, Spring ilovasi ulanish mijozlar uchun STOMP brokeriga aylanadi. Ushbu bo'limda server tomonida xabarlar oqimi tushuntiriladi.
spring-messaging moduli xabar almashinuvi dasturlari uchun asosiy qo'llab-quvvatlovchi vositalarni o'z ichiga oladi, ular Spring Integration loyihasida paydo bo'lgan, so'ngra kengroq foydalanishga Spring Framework ga qo'shilgan. Quyidagi ro'yxat mavjud xabar almashinuvi abstrahalaridan ba'zilari haqida qisqacha ma'lumot beradi:
-
Message: To'liq xabarni ifodalaydi, jumladan sarlavhalar va foydali ma'lumotlar.
-
MessageHandler: Xabarni ishlash kelishuvi.
-
MessageChannel: Xabar yuborish kelishuvi, yuboruvchilar va qabul qiluvchilarni bevosita bog'lashni ta'minlaydi.
-
SubscribableChannel:
MessageChannelbilanMessageHandlerabonentlari. -
ExecutorSubscribableChannel:
SubscribableChannel, xabar etkazish uchunExecutordan foydalanadi.
(Ya'ni, @EnableWebSocketMessageBroker anotatsiya) Java konfiguratsiyasi va XML nomlar bo'shlig'i konfiguratsiyasi (<websocket:message-broker>) oldingi komponentlardan xabarlar eshonishini tuzish uchun foydalanadi. Keyingi diagrammada ichki oddiy broker xabarlari faollashtirilganda foydalaniladigan komponentlar ko'rsatilgan:
Oldin diagrammada uchta xabar kanalini ko'rsatadi:
-
clientInboundChannel: WebSocket mijozlaridan olgan xabarlarni uzatish uchun. -
clientOutboundChannel: Server xabarlarini WebSocket mijozlariga jo'natish uchun. -
brokerChannel: Server tarafdagi ilova kodidan xabarlarni brokerga jo'natish uchun.
Keyingi diagrammada, obunalarni va xabarlar tarqatishni aniqlash uchun, tashqi broker (masalan, RabbitMQ) sozlangan komponenatlar ko'rsatilgan:
Oldingi diagrammalardagi asosiy farq "broker retranslyatori" dan foydalanishdir, u xabarlarni tashqi brokerga STOMP orqali TCP dan va brokerdan mijozlarga xabarlarni uzamiz.
Agar WebSocket aloqasidan xabarlar qabul qilinsa, ular STOMP kadrlariga dekodlanadi, Spring representationida Message ga o'giriladi va keyingi qayta ishlash uchun clientInboundChannel ga yuboriladi. Masalan, STOMP xabarlari, sarlavhalari /app bilan boshlanuvchilari @MessageMapping annotatsiyasi bilan belgilangan kontrollerdagi metodlarga marshrutlanishi mumkin, hmdash;olda, xabarlar /topic va /queue to'g'ridan-to'g'ri xabar brokeriga yo'naltirilishi mumkin.
@Controller annotatsiyasi bilan belgilangan kontroler, mijozdan kelgan STOMP xabarini qayta ishlovchi, brokerga brokerChannel orqali xabarni yuborishi mumkin, va broker xabarni obunachilariga clientOutboundChannel orqali tarqatadi. Ushbu kontroler HTTP so'rovlariga javob berishda xuddi shunday qilishi mumkin, shuning uchun mijoz HTTP POST usulini amalga oshirishi mumkin, va @PostMapping annotatsiyasi bilan belgilanadigan metod xabarni brokerga obunachilarga tarqatish uchun tarqatishi mumkin.
Biz bu jarayonni oddiy misolda kuzatishimiz mumkin. Quyidagi misol serverni sozlashni ko'rsatadi:
@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;
}
}
Oldingi misol quyidagi oqimni qo'llab-quvvatlaydi:
-
Mijoz
http://localhost:8080/portfolioga bog'lanadi va WebSocket ulanishi amalga oshirilgandan so'ng, STOMP kadrlari unga yuboriladi. -
Mijoz
/topic/greetingmanzil sarlavhasiga ega SUBSCRIBE kadrini jo'natadi. Qabul qilingach va dekodlanganidan so'ng, xabarclientInboundChannelga uzatiladi va brokerga marshrutlashadi, broker mijozning obunasini saqlaydi. -
Mijoz
/app/greetingga SEND kadrini jo'natadi./appprefiksi uni annotatsiyalangan kontrollerlarga marshrutlashtirishda yordam beradi./appprefiksi olib tashlanadi, qolgan maqsad/greeting@MessageMappingannotatsiyasi bilan belgilanadigan metodgaGreetingControllerda xaritlanadi. -
GreetingControllerdan qaytadigan qiymat SpringMessageishlab chiqarishida foydali ma'lumotlar bo'lib, qaytariladigan qiymatga asoslangan holda, standart maqsadli adresi xabarlar uchun/topic/greeting(kiritilgan manzildan/appo'zgartirish orqali olingan) yuvoriladi. Ushbu xabarbrokerChannelda uzatiladi va xabar brokeri tomonidan qayta ishlanadi. -
Xabar brokeri barcha mos obunachilarni topib, ularga
clientOutboundChannelorqali MESSAGE kadrini yuboradi, bu joyda kadrlar zarur bo'lsa, STOMP kadrlari sifatida kodlanadi va WebSocket ulanishi asosida yuboriladi.
Keyingi qismda anotatsiyalangan metodlar haqida batafsil ma'lumot, jumladan qo'llab-quvvatlanadigan argument turlari va qayta olinadigan qiymatlar haqida batafsil ma'lumotlar mavjud.
Anotatsiyalangan kontrollers
Ilovalar mijozlardan xabarlarni qayta ishlash uchun @Controller annotatsiyasi bilan belgilanadigan sinflardan foydalanishi mumkin. Bunday sinflar quyidagi mavzularda ko'rib chiqilganidek metodlarni @MessageMapping, @SubscribeMapping va @ExceptionHandler bilan belgilashlari mumkin:
-
@MessageMapping -
@SubscribeMapping -
@MessageExceptionHandler
@MessageMapping
@MessageMapping annotatsiyasidan, maqsadlari asosida xabarlarni marshrutlash uchun foydalanishingiz mumkin. Bu darajalarda metodlar va tiplar uchun qo'llab-quvvatlanadigan imkoniyat sifatida mavjud. Tiplar darajasida @MessageMapping annotatsiyasi umumiy xaritalashni belgilab o'tish uchun qo'llaniladi, bu esa kontrollerning barcha metodlari uchun xususiydir.
Standart bo'lib, xaritalash qiymatlari Ant uslubidagi yo'l shablonlari (masalan, /thing*, /thing/**), shuningdek, shablon o'zgaruvchilarni (masalan, /thing/{id}) o'z ichiga oladi. Ularning qiymatlari @DestinationVariable bilan belgilangan metod argumentlari orqali ko'rsatilishi mumkin. Ilovalar shuningdek, xabar maqsadli adres shablonlarini marshrutlashtirish uchun shablonlar o'zgarishiga o'tishi mumkin.
Qo'llab-quvvatlanadigan metod argumentlari
Quyidagi jadval metod argumentlarini ta'riflaydi:
| Metod argumenti | Tavsif |
|---|---|
|
|
To'liq xabarga kirish imkonini beradi. |
|
|
|
|
|
Tiplangan usul kirish orqali sarlavhalariga kirish imkonini beradi. |
|
|
Xabarlar yuklamasiga kirish imkonini beradi, shablonlangan Ushbu annotatsiyaning mavjudligi majburiy emas, chunki u default holatda qo'llaniladi, agar boshqa argumentlar mos kelmasa. Yuklama argumentlarini |
|
|
Maxsus sarlavha qiymatiga kirish imkonini beradi - agar kerak bo'lsa, |
|
|
Xabar ichidagi barcha sarlavhalarga kirish imkonini beradi. Ushbu argument |
|
|
Xabar manzil maqsadidan chiqarilgan shablon o'zgaruvchilariga kirish imkonini beradi. Qiymatlar deklaratsiya qilingan metod argument tipiga muvofiq, zarur bo'lganda o'zgartiriladi. |
|
|
HTTP tasdiqlash orqali WebSocket ulanishni belgilash vaqtida tizimga kirgan foydalanuvchini aks ettiradi. |
Qaytaruvchi qiymatlar
@MessageMapping annotatsiyasi bilan belgilangan metodning qaytaruvchi qiymati, default holatda, MessageConverter orqali serializatsiya qilinadi va Message orqali brokerChannelga yuboriladi va keyin obunachilarga tarqatiladi. Chiqish xabarining maqsadli adresi kiritilgan bilan bir xil, lekin /topic prefiksi bilan.
Chiqish xabarining maqsadli manzilini shablon orqali @SendTo va @SendToUser annotatsiyalari yordamida sozlashingiz mumkin. @SendTo anotatsiyasi bilan chiqish maqsadni yoki bir nechta maqsadlarni belgilash mumkin. @SendToUser anotatsiyasi yordamida faqat kiritilgan xabarga bog'liq foydalanuvchiga chiqish xabarini yo'naltirish mumkin.
Bitta metodda @SendTo va @SendToUser annotatsiyasini parallel ravishda qo'llash mumkin, bu esa sinf darajasida sifatida umumiy maqsadli manzil bo'ladi, va bunda ular metodlarning default holatida ishlaydi. Shu bilan birga, metod darajasida har qanday @SendTo yoki @SendToUser annotatsiyasi umumiy darajadagi har qanday shunga o'xshash annotatsiyalarni to'xtatadi.
Xabarlar asinxron ravishda qayta ishlana oladi, va @MessageMapping annotatsiyasi bilan belgilangan metod ListenableFuture, CompletableFuture yoki CompletionStage ni qaytarishi mumkin.
Shuni yodda tuting, @SendTo va @SendToUser annotatsiyalari shunchaki yordamchi choralar bo'lib, zarur bo'lganda SimpMessagingTemplate dan foydalanish o'rniga xizmat qilishi mumkin. Oldindan aytib o'tilganidek, murakkab stsenariylarda @MessageMapping bilan belgilangan metodlar to'g'ridan-to'g'ri SimpMessagingTemplate ga qaytishi mumkin. Bu qiymatni qaytarish yoki boshqa qo'shimcha harakatlar bilan birga amalga oshirilishi mumkin.
@SubscribeMapping
@SubscribeMapping annotatsiyasi @MessageMapping singari, lekin faqat obuna xabarlari uchun xaritalashni cheklaydi. Bu xuddi @MessageMapping annotatsiyasining metod argumentlarini qo'llab-quvvatlaydi. Ammo, default holatda, xabar to'g'ridan-to'g'ri mijozga (obunaga javoban) clientOutboundChannel orqali jo'natiladi, brokerga (brokerChannel) emas. @SendTo yoki @SendToUser annotatsiyasini qo'shish ushbu ishlash mantig'ini to'xtatadi va brokerga xabarlarni jo'natishga imkon beradi.
Bu qayerda amaliy? Faraz qiling, broker /topic va /queue ga xaritalangan, va ilova kontrollerlari /app ga xaritalangan. Ushbu konfiguratsiyada broker /topic va /queue obunalarini saqlaydi, endilikda obunalarni qayta ishlashda ilovaga ehtiyoj yo'q. Mijoz muayyan manzilga /app obunasi mumkin, va kontroler obunaga javoban qiymatni qaytishi mumkin, bu holda broker ishtirokida saqlanishi yoki obuna qayta ishlatilishi ham yo'q (ya'ni, bir martalik "request-response" (so'rov-javob) almashinuv)." Bu mexanizm ishlashning bir usuli dastlabki ma'lumotlar bilan foydalanuvchi interfeysini boshlash
Bu qayerda noamaliy? Agar broker va kontrollerlar bir xil manzil prefiksi bilan xaritalangan bo'lsa, shunday qilib, ikkalasi ham xabarlarni, jumladan obunalarni mustaqil ravishda ishlashi talab etilmasa, buni xaritalashning hojati yo'q. Kiruvchi xabarlar parallel ravishda qayta ishlanadi. Broker yoki kontroller, birinchi navbatda, qaysi biri xabarni qayta ishlashga kirishishini oldindan aytib bo'lmaydi. Agar obuna saqlangan va tarqatishga tayyor ekanligini xabar qilish maqsad qilinsa, mijoz serverni (oddiy broker qo'llab-quvvatlamaydi) qo'llab-quvvatlaydigan bo'lsa, qabul qilingan obunani tasdiqlash uchun so'rov qilishi kerak. Masalan, Java'dagi STOMP mijozidan foydalanib, quyidagicha qilish mumkin, tasdiqlashni qo'shing:
@Autowired
private TaskScheduler messageBrokerTaskScheduler;
// Initsializatsiya paytida...
stompClient.setTaskScheduler(this.messageBrokerTaskScheduler);
// Obuna paytida...
StompHeaders headers = new StompHeaders();
headers.setDestination("/topic/...");
headers.setReceipt("r1");
FrameHandler handler = ...;
stompSession.subscribe(headers, handler).addReceiptTask(receiptHeaders -> {
// Obuna tayyor...
});
Server tomonidan brokerChannel uchun ExecutorChannelInterceptor ni ro'yxatdan o'tkaza olasiz va afterMessageHandled metodini amalga oshirishingiz mumkin, bu esa obunani qo'llab-quvvatlashni o'z ichiga olgan xabarlardan so'ng chaqiriladi.
@MessageExceptionHandler
Ilova @MessageMapping bilan belgilangan metodlardan istisnolarni qo'llab-quvvatlash uchun @MessageExceptionHandler bilan belgilangan metodlardan foydalanishi mumkin. Istisnolarni to'g'ridan-to'g'ri annotatsiyada yoki agar istisnoning o'z nusxasiga kirish imkonini olish kerak bo'lsa, metod argumenti orqali e'lon qilish mumkin. Quyidagi misolda metod argumenti orqali istisno e'lon qilinadi:
@Controller
public class MyController {
// ...
@MessageExceptionHandler
public ApplicationError handleException(MyException exception) {
// ...
return appError;
}
}
@MessageExceptionHandler bilan belgilangan metodlar tizimli metod imzolarini qo'llab-quvvatlaydi va @MessageMapping bilan belgilangan metodlar singari metod argumentlari turlari va qayta olinadigan qiymatlarni qo'llab-quvvatlaydi.
Odatda @MessageExceptionHandler annotatsiyasi bilan belgilangan metodlar e'lon qilingan @Controller annotatsiyasi bilan belgilangan sinf (yoki sinf ierarxiyasi) doirasida qo'llaniladi. Agar bunday metodlar kengroq (barcha kontrollerlar) qo'llanishi kerak bo'lsa, @ControllerAdvice bilan belgilanadigan sinf ichida e'lon qilinishi mumkin. Bu Spring MVC'dagi mavjud qo'llab-quvvatlovchi vositalar bilan solishtirish mumkin.
Xabarlar jo'natish
Agar siz ilovaning qaysi qismlaridan mijozlarga xabarlar jo'natish kerak bo'lsa nima? Ilovaning har qanday komponenti brokerChannel orqali xabarlar jo'natishi mumkin. Buni amalga oshirishning oddiy usuli SimpMessagingTemplate'ni injeksiya qilish va undan xabarlar jo'natish uchun foydalanishdir. Odatda, bu quyidagi misolda ko'rsatilgandek tipga asoslanib injeksiya qilinadi:
@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);
}
}
Biroq, agar boshqa tipdagi bean mavjud bo'lsa (brokerMessagingTemplate) uni nomi bilan ham belgilash mumkin.
Oddiy broker
Tuzilgan ichki oddiy broker xabarlari mijozlardan obuna so'rovlarini qayta ishlaydi, ularni xotirada saqlaydi va mos keladigan manzil maqsadlariga ega bo'lgan xabarlarni ulangan mijozlarga tarqatadi. Broker manzil maqsad yo'llarini qo'llab-quvvatlaydi, shu jumladan Ant uslubidagi manzil maqsad shablonlariga obunalarni qo'llab-quvvatlaydi.
Agar vazifa to'xtatuvi konfiguratsiyalasa, oddiy broker STOMP heartbeat xabarlarini qo'llab-quvvatlaydi. Vazifa to'xtatuvchini konfiguratsialash uchun, siz o'z vazifa to'xtatuvchisini bean'dan e'lon qilishingiz mumkin TaskScheduler va uni MessageBrokerRegistry orqali o'rnatishingiz mumkin. Bundan tashqari, ilovaga qo'shilgan WebSocket'dagi ichki konfiguratsiya yordamida avtomatik e'lon qilinganidan foydalanishingiz mumkin, lekin bu holda siz @Lazy 'ni foydalanishingiz kerak WebSocket ilovasiga qo'shilgan va WebSocketMessageBrokerConfigurer mas uykini orasida tsikldan qaçınish uchun. Masalan:
@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);
// ...
}
}
Tashqi broker
Oddiy brokerdan boshlang'ich ishlatish juda oson, lekin U faqat STOMP buyruqlarning qismigina qo'llab-quvvatlaydi (ack, tasdiqlash olish va boshqa funksiyani qo'llab-quvvatlamaydi) va oddiy xabarlarni etkazish sikli ishlatadi, shuningdek cluster uchun mos emas. To'liq broker orqali ilovalarni rivojlantirish mumkin We can upgrade applications for complete use.
STOMP tanlangan broker (masalan, RabbitMQ, ActiveMQ va boshqalar) bilan, brokerni o'rnating va STOMP qo'llab-quvvatlovi bilan uni ishga tushirishdan boshlang. Keyin Spring konfiguratsiyasida STOMP broker retranslyatorini (oddiy broker o'rniga) ishga tushirish mumkin.
Keyingi konfiguratsiya misolida to'liq xabarlar brokeri uchun ilova ko'rsatilgan:
@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");
}
}
Quyidagi misolda oldingi misoldan XML konfiguratsiya ekvivalentini ko'rsatadi:
<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>
Oldingi konfiguratsiyadagi STOMP broker retranslyatori Spring'dan MessageHandler bo'lib, brokerga xabarlarni uzatish orqali ularni qayta ishlaydi. Buning uchun u broker bilan TCP ulanishlarni amalga oshiradi, unga barcha xabarlarni uzatadi va keyin brokerdan olingan barcha xabarlarni client WebSocket'da uzatadi. Bu, asosan, "retranslyator" sifatida harakat qiladi, har ikki yo'nalishda xabarlarni uzatadi.
io.projectreactor.netty:reactor-netty va
io.netty:netty-all bog'lanmalarni qo'shing.
Bundan tashqari, ilova komponentlari (masalan, HTTP so'rovlarini ishlovchi metodlar, biznes-servislar va boshqa) retranslyator brokeriga xabarlar jo'natishi mumkin.
Asosan, retranslyator broker xabarlarni ishonchli va miqyosi kattaga etkazish imkoniyatini taqdim etadi.
Broker bilan ulanish
STOMP broker retranslyatori broker bilan bitta "tizim" TCP ulanishini qo'llab-quvvatlaydi. Ushbu ulanish faqat server tarafidagi ilovadan chiqadigan xabarlar uchun ishlatiladi, lekin qabul qilish uchun emas. Siz ushbu ulanish uchun STOMP ma'lumotlarini (ya'ni, STOMP kadrlarida login va passcode sarlavhalarini) konfiguratsiya qilishingiz mumkin. Bu XML nomlar bo'shlig'ida va Java konfiguratsiyasida ko'rsatilgan, unda systemLogin va systemPasscode xususiyatlari ko'rsatilgan, va default qiymatlar guest va guest hisoblanadi.
STOMP broker retranslyatori har bir client WebSocket ulanishi uchun alohida TCP ulanish yaratishda STOMP ma'lumotlarini qo'llab-quvvatlaydi. Bu XML nomlar bo'shlig'ida va Java konfiguratsiyasida clientLogin va clientPasscode xususiyatlari sifatida ko'rsatilgan bo'lib, standard qiymatlar guest va guest hisoblanadi.
CONNECT kadrlarida
login va
passcode sarlavhalarini, brokerga ularni client nomidan uzatgan holda, sozlaydi. Shuning uchun, WebSocket mijozlariga xavfsizlik sarlavhalarini qo'ymasa ham bo'ladi. Ular e'tiborsiz qilinadi. WebSocket mijozlar HTTP taklifini tasdiqlash orqali WebSocket nuqtasini himoya qilishi kerak va mijozning identifikatsiyasini aniqlashi kerak.
STOMP broker retranslyatori "tizim" TCP ulanish orqali brokerga uzatiladigan va undan olingan heartbeat xabarlari uzatadi. Ular xabar yuborish va o'zaro tushirish intervalini sozlashingiz mumkin (default 10 soniya). Agar broker bilan ulanish yo'qolsa, broker retranslyatori ulanishni qayta tiklashga harakat qiladi, bu amalga oshguncha har 5 soniyada harakat qiladi.
Har qanday Spring bean ApplicationListener<BrokerAvailabilityEvent>'ni amalga oshirishi mumkin "tizim" ulanish broker bilan yo'qolar va keyin qayta tiklansa xabar olish uchun. Masalan, aktsiya kotirovka xizmati, aktsiya kotirovkasini tarqatayotgan, xabarlarni jo'natishni to'xtatishi mumkin, agar "tizim" ulanish faol bo'lmasa.
Default holda, STOMP broker retranslyatori brokerga "xost" va "port"ni ulanish, qayta tiklashda, o'sha xost va portni tanlab ulanadi. Agar ulanganda turli manzillar taqdim etish kerak bo'lsa, belgilangan xost va port o'rniga bir manzillar yetkazib beruvchini sozlashingiz mumkin. Quyidagi misol qanday qilish mumkinligini ko'rsatadi:
@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());
}
}
Shuningdek, broker retranslyatori STOMP'ni virtualHost xususiyati orqali konfiguratsiya qilishingiz mumkin. Ushbu xususiyatning qiymati har bir CONNECT kadrlarining host sarlavhasiga o'rnatilib, foydalidir (masalan, bulutli muhitda, TCP ulanishi o'rnatadigan real xost, bulutli STOMP xizmatini taqdim etgan xostdan farq qilishi mumkin).
Punktlar ajratkich sifatida
@MessageMapping annotatsiyasi bilan belgilangan metodlar qachon xabarlarga yo'naltirilsa, ular AntPathMatcher orqali xaritalanadi. Default holda, yo'l shablonlari koslash (/) ajratkichidan foydalanishini kutadi. Bu web ilovalar uchun HTTP URL manziliga o'xshab yaxshi kelishuvdir. Ammo agar siz, xabar almashish uchun kelishuvlarga ko'proq mos bo'lsangiz, xaritalash uchun ajratkich sifatida punkt (.) foydalanishni o'zgartirishingiz mumkin.
Quyidagi Java konfiguratsiyalari misolida qanday qilish mumkinligini ko'rsatadi:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
// ...
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setPathMatcher(new AntPathMatcher("."));
registry.enableStompBrokerRelay("/queue", "/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
Quyidagi XML konfiguratsiyasi misolida oldingi misoldan ko'rsatilgan:
<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>
Shundan so'ng, kontroler @MessageMapping anotatsiyasi bilan belgilangan metodlarda ajratkich sifatida punkt (.) ishlatishi mumkin, quyidagi misolda ko'rsatilganidek:
@Controller
@MessageMapping("red")
public class RedController {
@MessageMapping("blue.{green}")
public void handleGreen(@DestinationVariable String green) {
// ...
}
}
Endi mijoz xabarni /app/red.blue.green123 manziliga jo'natishi mumkin.
Oldingi misolda biz "broker retranslyatori" uchun prefikslarni o'zgartirmadik, chunki ular butunlay tashqi xabar brokeriga bog'liq. Tanlagan brokeringizning STOMP hujjatlari sahifalariga, broker manzil maqsadlari uchun qanday kelishuvlarni qo'llab-quvvatlashini bilish uchun murojaat qiling.
Biroq, "oddiy broker" muayyan PathMatcher ga tayanadi, shuning uchun siz ajratkichni o'zgartirsangiz, ushbu o'zgarish brokerga ham tatbiq etiladi, xabardagi manzil maqsadlari qanday qilib obunalar shablonlari bilan xaritalanishiga.
Tasdiqlash
STOMP xabar almashinuv sessiyasi ustiga WebSocket har bir HTTP so'roviga boshlanadi. Bu WebSocket protokoli ustiga web-socketlarga o'tish so'rovi (ya'ni, WebSocket orqali aloqani tasdiqlash) yoki SockJS orqali uzatish mexanizmlariga qator HTTP so'rovlari bo'lishi mumkin.
Ko'plab web ilovalar HTTP so'rovlari xavfsizligini ta'minlash uchun autentifikatsiya va ruxsat tizimiga ega. Odatda foydalanuvchi Spring Security orqali biron-bir mexanizmdan (masalan, kirish sahifasi orqali, asosiy HTTP autentifikatsiya yoki boshqa) autentifikatsiya qilinib, HTTP sessiya doirasida xavfsizlik tizimi orqali davom ettiriladi va keyingi so'rovlar asosan cookie orqali bir xil sessiya kerakligini bildiradi.
Shu maqsadda WebSocket yoki SockJS uzatish mexanizmlariga tajorat yuzasidan, odatda, HttpServletRequest#getUserPrincipal() orqali mavjud autentifikatsiya qilingan foydalanuvchi mavjud bo'ladi. Spring avtomatik ravishda ushbu foy
GO TO FULL VERSION