ãã ããããã¯ã¢ãããªãã·ã§ã³ã䜿çšããŠããåé¡ã¯æ®ããŸãã ãœã±ããã¯ããªãäœã¬ãã«ã®æœè±¡åã§ãããWebã¢ããªã±ãŒã·ã§ã³ã®å€§éšåã¯ä»æ¥ã®ãœã±ããã«é©åããŠããŸããã ãã®ãããWebSocketã¯ãHTTPã§ã®TCPã®äœ¿çšæ¹æ³ãšåæ§ã«ãWebSocketã§ã®é«ã¬ãã«ãããã³ã«ã®äœ¿çšãåºæ¬çã«èš±å¯ïŒããã³æšå¥šïŒãããµããããã³ã«ã¡ã«ããºã ãå®çŸ©ããŸãã
Spring Framework 4.0 M2ã®2çªç®ã®äžéãªãªãŒã¹ã§ã¯ãWebSocketäžã§é«ã¬ãã«ã®ã¡ãã»ãŒãžã³ã°ãããã³ã«ã䜿çšã§ããŸãã ãããå®èšŒããããã«ããµã³ãã«ã¢ããªã±ãŒã·ã§ã³ãåæããŸãã
æ ªåŒããŒããã©ãªãªã¢ããª
Githubã§å©çšã§ãããã®ãã¹ãã¢ããªã±ãŒã·ã§ã³ã䜿çšãããšããŠãŒã¶ãŒã¯ããžã·ã§ã³ã®ããŒããã©ãªãªãã¢ããããŒãããããæ ªåŒã売買ãããã§ããŸãã äŸ¡æ ŒèŠç©ããéä¿¡ããäœçœ®ã®æŽæ°ã衚瀺ããŸãã ããã¯ããªãåçŽãªã¢ããªã±ãŒã·ã§ã³ã§ãã ãã ãããã©ãŠã¶ããŒã¹ã®ã¡ãã»ãŒãžã³ã°ã¢ããªã±ãŒã·ã§ã³ã§çºçããå¯èœæ§ã®ããå€ãã®äžè¬çãªã¿ã¹ã¯ã«ã€ããŠèª¬æããŸãã
ãã®ãããªã¢ããªã±ãŒã·ã§ã³ãã©ã®ããã«æ£ç¢ºã«å®è£ ããŸããïŒ HTTPããã³RESTã§ã¯ãå®è¡ããå¿ èŠãããããšãè¡šçŸããããã«URLããã³HTTPã¡ãœããã«äŸåããããšã«æ £ããŠããŸãã ãããããœã±ãããšã¡ãã»ãŒãžã®æãããããŸããã ã¡ãã»ãŒãžã®å¯Ÿè±¡è ãšãã®æå³ãç¥ãæ¹æ³
ãã®ã»ãã³ãã£ã¯ã¹ãè¡šçŸããã«ã¯ããã©ãŠã¶ãšãµãŒããŒãå ±éã®ã¡ãã»ãŒãžåœ¢åŒã«åæããå¿ èŠããããŸãã 圹ç«ã€å¯èœæ§ã®ãããããã³ã«ãããã€ããããŸãã ãã®ãªãªãŒã¹ã§ã¯ãã·ã³ãã«ããšå¹ åºããµããŒãã®ããã«STOMPãéžæããŸããã
ã·ã³ãã«/ã¹ããªãŒãã³ã°ããã¹ãæåã¡ãã»ãŒãžã³ã°ãããã³ã«ïŒSTOMPïŒ
STOMPã¯éåžžã«ã·ã³ãã«ãªã¡ãã»ãŒãžã³ã°ãããã³ã«ã§ãã HTTPã§ã¢ãã«åããããã¬ãŒã ã«åºã¥ããŸãã ãã¬ãŒã ã¯ãã³ãã³ãããªãã·ã§ã³ã®ããããŒãããã³ãªãã·ã§ã³ã®æ¬äœã§æ§æãããŸãã
ããšãã°ãæ ªäŸ¡ããŒããã©ãªãªã¢ããªã±ãŒã·ã§ã³ã¯çžå Žãéä¿¡ã§ããã¯ã©ã€ã¢ã³ãã¯SUBSCRIBEãã¬ãŒã ãéä¿¡ããŸããããã§ããå®å ãèŠåºãã¯ããµãã¹ã¯ã©ã€ãããå 容ãæ£ç¢ºã«ç€ºããŸãã
SUBSCRIBE id:sub-1 destination:/topic/price.stock.*
æ ªäŸ¡ãå©çšå¯èœã«ãªããšããã«ããµãŒããŒã¯ã察å¿ãããå®å ããšãµãã¹ã¯ãªãã·ã§ã³èå¥åãããã³ãã³ã³ãã³ãã¿ã€ããããããŒãšæ¬æãå«ãMESSAGEãã¬ãŒã ãéä¿¡ããŸãã
MESSAGE subscription:sub-1 message-id:wm2si1tj-4 content-type: application/json destination:/topic/stocks.PRICE.STOCK.NASDAQ.EMC {\"ticker\":\"EMC\",\"price\":24.19}
ããããã¹ãŠãã©ãŠã¶ãŒã§çµã¿åãããã«ã¯ã stomp.jsãšSockJSã¯ã©ã€ã¢ã³ãã䜿çšããŸã ã
var socket = new SockJS('/spring-websocket-portfolio/portfolio'); var client = Stomp.over(socket); var onConnect = function() { client.subscribe("/topic/price.stock.*", function(message) { // }); }; client.connect('guest', 'guest', onConnect);
ããã¯é倧ãªé²æ©ã§ãïŒ ã¯ã©ã€ã¢ã³ãåŽã§æšæºã®ã¡ãã»ãŒãžåœ¢åŒãšãµããŒããæäŸããŠããŸãã
ããã§ããã«ç§»åã§ããŸã-ãµãŒããŒåŽã«ã
ã¡ãã»ãŒãžãããŒã«ãŒ
ã¡ãã»ãŒãžãããŒã«ãŒã¯ãRabbitMQãActiveMQãªã©ã®åŸæ¥ã®ãããŒã«ãŒéã§ã¡ãã»ãŒãžã転éãããå žåçãªãµãŒããŒãœãªã¥ãŒã·ã§ã³ã§ãã ãã¹ãŠã§ã¯ãªãã«ããŠããã»ãšãã©ãTCPãä»ããSTOMPããµããŒãããäžéšã¯WebSocketããµããŒãããŸãããRabbitMQã¯æãå é²çã§ãããSockJSã§ãåäœããŸãã
ã¢ãŒããã¯ãã£ã¯æ¬¡ã®ããã«ãªããŸãã
ããã¯ä¿¡é Œæ§ãé«ãã¹ã±ãŒã©ãã«ãªãœãªã¥ãŒã·ã§ã³ã§ãããããããç®ã®åã®ã¿ã¹ã¯ã«ã¯æé©ã§ã¯ãããŸããã ã¡ãã»ãŒãžãããŒã«ãŒã¯äžè¬ã«äŒæ¥å ã§äœ¿çšãããŸãã ãããã¯ãŒã¯ã«çŽæ¥å ¬éããããšã¯ãçæ³çãªãœãªã¥ãŒã·ã§ã³ãåŒãä»ããŸããã
RESTã¢ãããŒãããäœããåŠãã å Žåãã·ã¹ãã ãããŒã¿ããŒã¹ããã€ã¹ããŸãã¯ãã¡ã€ã³ã¢ãã«ã®å®è£ ã®è©³çŽ°ãæããã«ãã䟡å€ã¯ãããŸããã
ããã«ãJavaéçºè ã¯ãããããã¢ã¯ã»ã¹æš©ãæ€èšŒãæ§æããã¢ããªã±ãŒã·ã§ã³ããžãã¯ãè¿œå ããå¿ èŠããããŸãã ã¡ãã»ãŒãžãããŒã«ãŒã«ããã¢ãããŒãã§ã¯ãã¢ããªã±ãŒã·ã§ã³ãµãŒããŒã¯ãããŒã«ãŒã®èåŸã«ãããŸããããã¯ãã»ãšãã©ã®Webéçºè ãæ £ããŠãããã®ãšã¯å€§ããç°ãªããŸãã
ãããã socket.ioã®ãããªã©ã€ãã©ãªã人æ°ãããçç±ã§ãã ããã¯åçŽã§ãWebã¢ããªã±ãŒã·ã§ã³ã®ããŒãºã察象ãšããŠããŸãã äžæ¹ãã¡ãã»ãŒãžåŠçã®èŠ³ç¹ããã¡ãã»ãŒãžãããŒã«ãŒã®æ©èœãç¡èŠããã¹ãã§ã¯ãããŸããã圌ãã¯ãããæ¬åœã«åŸæã§ã-é£ãããžã¬ã³ãã§ãã äž¡æ¹ã®é·æã掻çšããŠãã ããã
ã¢ããªã±ãŒã·ã§ã³+ã¡ãã»ãŒãžãããŒã«ãŒ
å¥ã®ã¢ãããŒãã¯ãçä¿¡ã¡ãã»ãŒãžãåŠçããWebã¯ã©ã€ã¢ã³ããšãããŒã«ãŒéã®ä»²ä»ãšããŠæ©èœããã¢ããªã±ãŒã·ã§ã³ãäœæããããšã§ãã ã¯ã©ã€ã¢ã³ããããããŒã«ãŒãžã®ã¡ãã»ãŒãžã¯ãã¢ããªã±ãŒã·ã§ã³ãä»ããŠéä¿¡ã§ããŸããè¿ä¿¡ã¡ãã»ãŒãžã¯ãã¢ããªã±ãŒã·ã§ã³ãä»ããŠã¯ã©ã€ã¢ã³ãã«æž¡ãããŸãã ããã«ãããã¢ããªã±ãŒã·ã§ã³ã¯ã¡ãã»ãŒãžã®ã¿ã€ããšããããŒã®ãå®å ããå€å¥ã§ããŸãããã®åŸãã¡ãã»ãŒãžãèªåã§åŠçãããããããŒã«ãŒã«ãªãã€ã¬ã¯ãããããšã決å®ãããŸãã
ãã®ã¢ãããŒããéžæããŸããã ãããããè¯ã説æããããã«ãããã€ãã®ã·ããªãªããããŸãã
ããžã·ã§ã³ã®ããŒããã©ãªãªãããŒããã
- 顧客ã¯ããžã·ã§ã³ã®ããŒããã©ãªãªãèŠæ±ããŸã
- ã¢ããªã±ãŒã·ã§ã³ã¯ããµãã¹ã¯ãªãã·ã§ã³ã®ããŒã¿ãããŒãããŠè¿ãããšã§ãªã¯ãšã¹ããåŠçããŸã
- ã¡ãã»ãŒãžãããŒã«ãŒã¯ãã®å¯Ÿè©±ã«é¢äžããŠããŸãã
æ ªäŸ¡ã®ãµãã¹ã¯ãªãã·ã§ã³
- 顧客ããµãã¹ã¯ãªãã·ã§ã³èŠæ±ãéä¿¡ããŸã
- ã¢ããªã±ãŒã·ã§ã³ã¯ãããŒã«ãŒã«ã¡ãã»ãŒãžãéä¿¡ããŸã
- ã¡ãã»ãŒãžãããŒã«ãŒã¯ãã¹ãŠã®çœ²åæžã¿ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããŸã
æ ªäŸ¡ã®ååŸ
- QuoteServiceã¯æ ªäŸ¡æ å ±ã¡ãã»ãŒãžããããŒã«ãŒã«éä¿¡ããŸã
- ã¡ãã»ãŒãžãããŒã«ãŒã¯ãã¹ãŠã®çœ²åæžã¿ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããŸã
ååŒ
- 顧客ãååŒãªã¯ãšã¹ããéä¿¡ããŸã
- ã¢ããªã±ãŒã·ã§ã³ã¯ãããåŠçããããã¹ãŠã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯TradeServiceãééããŸã
- ã¡ãã»ãŒãžãããŒã«ãŒã¯ãã®å¯Ÿè©±ã«é¢äžããŠããŸãã
æŽæ°ãããäœçœ®ã®ååŸ
- TradeServiceã¯ããããŒã«ãŒã®ãã¥ãŒå ã®äœçœ®ã®æŽæ°ã«é¢ããã¡ãã»ãŒãžãéä¿¡ããŸã
- ã¡ãã»ãŒãžãããŒã«ãŒã¯äœçœ®ã®æŽæ°ãã¯ã©ã€ã¢ã³ãã«éä¿¡ããŸã
- ç¹å®ã®ãŠãŒã¶ãŒãžã®ã¡ãã»ãŒãžã®éä¿¡ã«ã€ããŠã¯ã以äžã§è©³ãã説æããŸãã
å³å¯ã«èšãã°ãã¡ãã»ãŒãžãããŒã«ãŒã®äœ¿çšã¯ãªãã·ã§ã³ã§ãã ãåçŽãªãããã¯ã¹åããã代æ¿æ段ãæäŸããŸãã ãã ããã¹ã±ãŒã©ããªãã£ãšè€æ°ã®ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒã§å±éããå Žåã¯ãã¡ãã»ãŒãžãããŒã«ãŒã®äœ¿çšããå§ãããŸãã
ã³ãŒãã¹ãããã
ãµãŒããŒãšã¯ã©ã€ã¢ã³ãã®ã³ãŒãã®äŸãèŠãŠã¿ãŸãããã
ããã¯ãportfolio.jsããã®ããžã·ã§ã³ã®ããŒããã©ãªãªã®ãªã¯ãšã¹ãã§ãã
stompClient.subscribe("/app/positions", function(message) { self.portfolio().loadPositions(JSON.parse(message.body)); });
ãµãŒããŒåŽã§ã¯ã PortfolioControllerãèŠæ±ãæ€åºããããžã·ã§ã³ã®ããŒããã©ãªãªãè¿ããŸããããã¯ãWebã¢ããªã±ãŒã·ã§ã³ã§é »ç¹ã«äœ¿çšãããèŠæ±ãšå¿çã®çžäºäœçšã瀺ããŠããŸãã Spring Securityã䜿çšããŠãWebSocketãšã®ãã³ãã·ã§ã€ã¯ã«é¢é£ããæåã®1ã€ãå«ãHTTPèŠæ±ã以äžã®äŸã®ã¡ãœããã®åŒæ°ãšããŠä¿è·ãããããHttpServletRequestããååŸããããªã³ã·ãã«Spring SecurityãŠãŒã¶ãŒãæž¡ãããŸãã
@Controller public class PortfolioController { // ... @SubscribeEvent("/app/positions") public List<PortfolioPosition> getPortfolios(Principal principal) { String user = principal.getName(); Portfolio portfolio = this.portfolioService.findPortfolio(user); return portfolio.getPositions(); } }
ããã§ãportfolio.jsãååŒãªã¯ãšã¹ããéä¿¡ããŸãã
stompClient.send("/app/trade", {}, JSON.stringify(trade));
ãµãŒããŒåŽã§ã¯ãPortfolioControllerã¯å®è¡ã®ããã«ãããæž¡ããŸãã
@Controller public class PortfolioController { // ... @MessageMapping(value="/app/trade") public void executeTrade(Trade trade, Principal principal) { trade.setUsername(principal.getName()); this.tradeService.executeTrade(trade); } }
PortfolioControllerã¯ããŠãŒã¶ãŒã«ã¡ãã»ãŒãžãéä¿¡ããããšã«ãããäºæããªãäŸå€ãåŠçããããšãã§ããŸãã
@Controller public class PortfolioController { // ... @MessageExceptionHandler @ReplyToUser(value="/queue/errors") public String handleException(Throwable exception) { return exception.getMessage(); } }
賌èªããŠãããã¹ãŠã®é¡§å®¢ã«ã¡ãã»ãŒãžãéä¿¡ããã®ã¯ã©ãã§ããïŒ ãã®ãããQuoteServiceã¯ã¯ã©ãŒã¿ãéä¿¡ããŸãã
@Service public class QuoteService { private final MessageSendingOperations<String> messagingTemplate; @Scheduled(fixedDelay=1000) public void sendQuotes() { for (Quote quote : this.quoteGenerator.generateQuotes()) { String destination = "/topic/price.stock." + quote.getTicker(); this.messagingTemplate.convertAndSend(destination, quote); } } }
ãã®ãããTradeServiceã¯ååŒã®å®äºåŸã«ããžã·ã§ã³ã®æŽæ°ãéä¿¡ããŸãã
@Service public class TradeService { // ... @Scheduled(fixedDelay=1500) public void sendTradeNotifications() { for (TradeResult tr : this.tradeResults) { String queue = "/queue/position-updates"; this.messagingTemplate.convertAndSendToUser(tr.user, queue, tr.position); } } }
@RequestMapping
ãã...ãããããªããPortfolioControllerã«ã¯ã以åã«ãªã³ã©ã€ã³ã²ãŒã ãæ§ç¯ããéçºè ããã®ãã±ããã§ææ¡ããããã«ãSpring MVCã¡ãœããïŒ
@RequestMapping
ïŒãå«ãŸããŠããå ŽåããããŸãã
åŒçš
ã¯ãã[ã¡ãã»ãŒãž]ãããã³ã°ãšã¹ããªã³ã°mvcãããã³ã°ãçµ±åãããšè¯ãã§ãããã çµ±äžã§ããªãçç±ã¯ãããŸããã
ãŸããQuoteServiceãTradeServiceãšåæ§ã«ãSpring MVCã³ã³ãããŒã©ãŒã¡ãœãããã¡ãã»ãŒãžãæçš¿ã§ããŸãã
Springã¢ããªã±ãŒã·ã§ã³ã§ã®ã¡ãã»ãŒãžã³ã°ãµããŒã
é·ãéã Spring Integrationã¯ãããç¥ãããŠãããšã³ã¿ãŒãã©ã€ãºçµ±åãã¿ãŒã³ãšè»œéã®ã¡ãã»ãŒãžã³ã°ã®ããã®ãã¡ãŒã¹ãã¯ã©ã¹ã®æœè±¡åãæäŸããŸãã ãã®ãªãªãŒã¹ã®äœæ¥äžã«ãåŸè ããŸãã«ç§ãã¡ãä¿¡é Œããå¿ èŠããããã®ã§ããããšã«æ°ä»ããŸããã
ãã®çµæããããçºè¡šã§ããããšãå¬ããæããŸããSpringIntegrationã¿ã€ãã®ã»ãããæ°ããSpring Frameworkã¢ãžã¥ãŒã«ã«ç§»åããŸãããããã¯äºæ³ã©ããspring-messagingãšåŒã°ããŸãã MessageãMessageChannelãMessageHandlerãªã©ã®äž»èŠãªæœè±¡åã«å ããŠãã¢ãžã¥ãŒã«ã«ã¯ããã®æçš¿ã§èª¬æããæ°ããæ©èœããµããŒãããããã®ãã¹ãŠã®æ³šéãšã¯ã©ã¹ãå«ãŸããŠããŸãã
ããã念é ã«çœ®ããŠãStock Portfolioã¢ããªã±ãŒã·ã§ã³ã®å éšæ§é ã®å³ãèŠãŠã¿ãŸãããã
StompWebSocketHandlerã¯ãçä¿¡ã¯ã©ã€ã¢ã³ãã¡ãã»ãŒãžããã£ã¹ããããã£ãã«ã«é 眮ããŸãã ãã®ãã£ã³ãã«ã«ã¯3人ã®ãã£ã³ãã«ç»é²è ãããŸãã 1ã€ç®ã¯ã¢ãããŒã·ã§ã³ä»ãã¡ãœãããæ åœãã2ã€ç®ã¯STOMPãããŒã«ãŒã«ã¡ãã»ãŒãžãéä¿¡ãã3ã€ç®ã¯å®å ã¢ãã¬ã¹ãã¯ã©ã€ã¢ã³ãããµãã¹ã¯ã©ã€ãããäžæã®ååã®ãã¥ãŒã«å€æããããšã§åã ã®ãŠãŒã¶ãŒã®ã¡ãã»ãŒãžãåŠçããŸãã
ããã©ã«ãã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã¯ç¥ãåãã«æäŸããããã·ã³ãã«ãªããããŒã«ãŒã§åäœããŸãã READMEã§èª¬æãããŠããããã«ããããã¡ã€ã«ãã¢ã¯ãã£ãåããã³éã¢ã¯ãã£ãåããããšã«ããããã·ã³ãã«ãªããããŒã«ãŒãšãã«æ©èœã®ãããŒã«ãŒãéžæã§ããŸãã
å¥ã®å¯èœãªæ§æå€æŽã¯ã ExecutorããReactorããŒã¹ã®MessageChannelå®è£ ã«ç§»è¡ããããšã§ãã Reactorãããžã§ã¯ãã¯æè¿ãæåã®æ«å®ãªãªãŒã¹ããªãªãŒã¹ããã¢ããªã±ãŒã·ã§ã³ãšã¡ãã»ãŒãžãããŒã«ãŒéã®TCPæ¥ç¶ã®ç®¡çã«ã䜿çšãããŠããŸãã
ããã§ã¯ã æ°ãã Spring Securityæ§æãå«ãå®å šãªã¢ããªã±ãŒã·ã§ã³æ§æã確èªã§ããŸãã ãŸãã STSã®æ§æã®ãµããŒãã®æ¹åã«ã€ããŠãèå³ããããŸãã
åã ã®ãŠãŒã¶ãŒã«ã¡ãã»ãŒãžãéä¿¡ãã
ãµã€ã³ã¢ãããããã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããæ¹æ³ãç解ããã®ã¯ç°¡åã§ãããã£ã³ãã«ã«ã¡ãã»ãŒãžãéä¿¡ããã ãã§ãã ããå°ãè€éãªã®ã¯ãç¹å®ã®ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããç¶æ³ã§ãã ããšãã°ãäŸå€ããã£ãããããšã©ãŒã¡ãã»ãŒãžãéä¿¡ããããšããŸãã ãŸãã¯ããã©ã³ã¶ã¯ã·ã§ã³ã®å®äºã®ç¢ºèªãåãåãããŠãŒã¶ãŒãåã°ãããå Žåã
åŸæ¥ã®ã¡ãã»ãŒãžã³ã°ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã®ã¿ã¹ã¯ã¯éåžžãäžæçãªãã¥ãŒãäœæããå¿çãæå³ãããã¹ãŠã®ã¡ãã»ãŒãžã«ãreply-toãããããŒãèšå®ããããšã§å®çŸãããŸãã åäœããŸãããããªãããã°ã£ãŠããŸãã ã¯ã©ã€ã¢ã³ãã¯ã該åœãããã¹ãŠã®ã¡ãã»ãŒãžã«å¿ èŠãªããããŒãèšå®ããããšãå¿ããŠã¯ãªããããµãŒããŒã¢ããªã±ãŒã·ã§ã³ã¯ããããç£èŠããå¿ èŠãããå ŽåããããŸãã ãã®æ å ±ã¯å©çšã§ããªãå ŽåããããŸãïŒããšãã°ãã¡ãã»ãŒãžã³ã°ã®ä»£ããã«HTTP POSTã䜿çšãããŠããå ŽåïŒã
ãã®èŠä»¶ããµããŒãããããã«ãæ¥ç¶ãããåã¯ã©ã€ã¢ã³ãã«äžæã®ãã¥ãŒãµãã£ãã¯ã¹ãéä¿¡ããŸãã ãã®åŸããµãã£ãã¯ã¹ãèå¥åã«è¿œå ããŠãäžæã®ãã¥ãŒåãäœæã§ããŸãã
client.connect('guest', 'guest', function(frame) { var suffix = frame.headers['queue-suffix']; client.subscribe("/queue/error" + suffix, function(msg) { // }); client.subscribe("/queue/position-updates" + suffix, function(msg) { // }); });
次ã«ããµãŒããŒåŽã§ã
@ReplyToUser
ã¢ãããŒã·ã§ã³ã
@MessageExceptionHandler
ããŒã¯ãããã¡ãœããïŒãŸãã¯ä»ã®ã¡ãã»ãŒãžåŠçã¡ãœããïŒã«è¿œå ããæ»ãå€ãã¡ãã»ãŒãžãšããŠéä¿¡ã§ããŸãã
@MessageExceptionHandler @ReplyToUser(value="/queue/errors") public String handleException(Throwable exception) { // ... }
TradeServiceãªã©ã®ä»ã®ãã¹ãŠã®ã¯ã©ã¹ã¯ãmessagingTemplateã䜿çšããŠåãããšãå®çŸã§ããŸãã
String user = "fabrice"; String queue = "/queue/position-updates"; this.messagingTemplate.convertAndSendToUser(user, queue, position);
ã©ã¡ãã®å Žåããæ£ãããã¥ãŒåã埩å ããããã«ãå éšã«ãŠãŒã¶ãŒãã¥ãŒãµãã£ãã¯ã¹ããããŸãïŒæ§ææžã¿ã®UserQueueSuffixResolverãäœ¿çš ïŒã çŸæç¹ã§ã¯ãåçŽãªãªãŸã«ãã®å®è£ ã¯1ã€ã ãã§ãã ãã ãããŠãŒã¶ãŒãŸãã¯å¥ã®ã¢ããªã±ãŒã·ã§ã³ãµãŒããŒãæ¥ç¶ãããŠãããã©ããã«é¢ä¿ãªããæ©èœããµããŒãããRedisããŒã¹ã®å®è£ ãè¿œå ããã®ã¯éåžžã«ç°¡åã§ãã
çµè«
ãããæ°ããæ©èœã®æçãªçŽ¹ä»ã«ãªãã°å¹žãã§ãã æçš¿ãããã«é·ããã代ããã«ã äŸãæ€èšããŠãäœæããã¢ããªã±ãŒã·ã§ã³ãŸãã¯äœæããã¢ããªã±ãŒã·ã§ã³ã«é©çšããããšããå§ãããŸãã ããã¯ããã£ãŒãããã¯ã®çæ³çãªææã§ãã 9æäžæ¬ã«ãªãªãŒã¹åè£ãã©ã®ããã«èšç»ããŸããã