spring amqp股票交易应用DeferredResult

参考:
spring-framework-reference.pdf:17.3 Implementing Controllers的Asynchronous Request Processing
Adding Long Polling to an Existing Web Application:https://spring.io/blog/2012/05/14/spring-mvc-3-2-preview-adding-long-polling-to-an-existing-web-application


关于DeferredResult的应用场景,spring-framework-reference.pdf有一段话:A second option is for the controller to return an instance of DeferredResult.In this case the return value will also be produced from a separate thread. However, that thread is not known to Spring MVC.For example the result may be produced in response to some external event such as a JMS message,a scheduled task.
前面介绍spring amqp股票交易的第二点:由客户端先初始化,服务端处理的请求-回复"股票交易"的交互.
在前面的例子
1.先post请求到controller的trade方法,异步发送消息到amqp的服务端,就马上直接返回到页面前端.
2.因为是异步,没法马上得到股票响应信息的,所以写了个传统轮询每隔2s去再拿股票响应信息,直到拿到这个信息,轮询才停止.
这个过程,页面与服务端(controller)的请求来来回回好几次.


如果使用DeferredResult,是非常适合的,流程如下:
1.先post请求到controller的trade方法,异步发消息到amqp的服务端,这时response是打开的,还没有提交.
2.amqp的服务端接到客户端发过来的请求,处理(ServerHandler.handleMessage(TradeRequest))完再发送回客户端,客户端的监听器接收再处理(QuoteController.handleTrade(TradeResponse),我个人把这个处理提取到ClientHandler.handleMessage(TradeResponse)).
3.在这个方法,把结果通过DeferredResult.setResult()设置,这时服务端的response开始提交了,再返回到页面.

这个过程,从页面到controller只发了一次请求.

下面是大概的代码修改过程.
1.从页面发起的post请求:

$('#tradeForm').submit(function () {
        $('#messages').text('');
        $.post($('#tradeForm').attr("action"), $('#tradeForm').serialize(),
                function(response) {
                if (response && response.requestId) {
                        $('#confirmations').append($.mustache(confirmation, {response : response}));
                } else {
                        $('#messages').html("<p>Invalid response.</p>");
                }
        });
        return false;
})
2.按前文修改spring mvc支持处理异步请求.即在AbstractDispatcherServletInitializer修改filter和servlet的asyncSupport为true(其中servlet的asyncSupport已默认为true).

3.Controller接收页面请求处理的方法.

@RequestMapping(value = "/trade", method = RequestMethod.POST)
    @ResponseBody
    public DeferredResult<TradeResponse> trade(@ModelAttribute TradeRequest tradeRequest) {
        String ticker = tradeRequest.getTicker();
        Long quantity = tradeRequest.getQuantity();
        if (quantity == null || quantity <= 0 || !StringUtils.hasText(ticker)) {
            return null;
        }
        // Fake rest of request while UI is basic
        tradeRequest.setAccountName("ACCT-123");
        tradeRequest.setBuyRequest(true);
        tradeRequest.setOrderType("MARKET");
        final String requestId=UUID.randomUUID().toString();
        tradeRequest.setRequestId(requestId);
        tradeRequest.setUserName("Joe Trader");
        tradeRequest.setUserName("Joe");
        this.stockServiceGateway.send(tradeRequest);

        DeferredResult<TradeResponse> result = new DeferredResult<TradeResponse>(30000l,null);
        final Map<String, DeferredResult> resultMap=clientHandler.getSuspendedTradeRequests();
        resultMap.put(requestId, result);
        result.onCompletion(new Runnable() {
            @Override
            public void run() {
                resultMap.remove(requestId);
            }
        });
        return result;
    }


这里就是向amqp服务端发送消息,DeferredResult还没有调用setResult方法,response先不提交.注意DeferredResult这个构造函数,请求时间超过第一个参数设置的时间,则返回第二个参数作为结果.对于onCompletion回调,当异步请求完成时(包括超时和网络错误),这个方法将被调用,这个方法用于检测一个不可用的DeferredResult实例是非常有用的.

4.amqp服务端的处理修改,将ExecutionVenueServiceStub.executeTradeRequest()方法的response.setRequestId(request.getId());改为response.setRequestId(request.getRequestId());这个requestId是我全程跟踪这个服票交易消息是属于那一个请求的.
5.回到amqp客户端处理ClientHandler.handleMessage(TradeResponse):
private Map<String, DeferredResult> suspendedTradeRequests = new ConcurrentHashMap<String, DeferredResult>();
public Map<String, DeferredResult> getSuspendedTradeRequests() {
	return suspendedTradeRequests;
}
public void handleMessage(TradeResponse response) {
	logger.info("Client received: " + response);
	DeferredResult<TradeResponse> deferredResult=suspendedTradeRequests.get(response.getRequestId());
	//以防重启spring mvc服务器,延迟的信息被侦察到延时处理,从map里get为null
	if (deferredResult!=null){
		deferredResult.setResult(response);
	}
}
这里得到相应的DeferredResult,再调用setResult,就会把response提交,回到页面显示.


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值