Spring MVC的异步模式

典型的同步模式:





浏览器发起请求,Web服务器开一个线程处理,处理完把处理结果返回浏览器。绝大多数Web服务器都如此般处理。现在想想如果处理的过程中需要调用后端的一个业务逻辑服务器





请求处理线程会在Call了之后等待Return,自身处于阻塞状态。这也是绝大多数Web服务器的做法,一般来说这样做也够了,一来长时间处理服务调用通常不多,二来请求数其实也不多。要不是这样的话,这种模式会出现什么问题——会出现的问题就是请求处理线程的短缺!因为请求处理线程的总数是有限的,如果类似的请求多了,所有的处理线程处于阻塞的状态,那新的请求也就无法处理了,也就所谓影响了服务器的吞吐能力。要更加好地发挥服务器的全部性能,就要使用异步,这也是标题上所说的高性能的关键



最大的不同在于请求处理线程对后台处理的调用使用了“invoke”的方式,就是说调了之后直接返回,而不等待,这样请求处理线程就自由了,它可以接着去处理别的请求,当后端处理完成后,会钩起一个回调处理线程来处理调用的结果,这个回调处理线程跟请求处理线程也许都是线程池中的某个线程,相互间可以完全没有关系,由这个回调处理线程向浏览器返回内容。这就是异步的过程。

带来的改进是显而易见的,请求处理线程不需要阻塞了,它的能力得到了更充分的使用,带来了服务器吞吐能力的提升。


Spring MVC的使用——DefferedResult



使用的Servlet版本是3.1.0Spring MVC版本是4.2.3,建议使用最新的版本。

由于Spring MVC的良好封装,异步功能使用起来出奇的简单。传统的同步模式的Controller是返回ModelAndView,而异步模式则是返回DeferredResult<ModelAndView>




longTimeAsyncCallService是一个模拟长时间异步调用的服务类,调用之,立即返回,当它处理完成时候,就钩起一个线程调用我们提供的回调函数,这跟3”描述的一样,它的代码如下:








输出结果:




处理超时

如果长时间处理任务一直没返回,那我们也不应该让客户端无限等下去啊,总归要弄个

出来



 

@RequestMapping(value="/longtimetask",method = RequestMethod.GET)

public WebAsyncTask longTimeTask(){

   System.out.println("/longtimetask被调用 thread id is : " + Thread.currentThread().getId());

   Callable<ModelAndView> callable = newCallable<ModelAndView>() {

       public ModelAndView call() throws Exception {

            Thread.sleep(3000); //假设是一些长时间任务

            ModelAndView mav = newModelAndView("longtimetask");

            mav.addObject("result","执行成功");

            System.out.println("执行成功 thread id is : " + Thread.currentThread().getId());

            return mav;

       }

   };

   

   

   WebAsyncTask asyncTask = new WebAsyncTask(2000, callable);

   asyncTask.onTimeout(

           new Callable<ModelAndView>() {

                public ModelAndView call()throws Exception {

                    ModelAndView mav = new ModelAndView("longtimetask");

                   mav.addObject("result", "执行超时");

                    System.out.println("执行超时 thread id is " +Thread.currentThread().getId());

                    return mav;

                }

           }

   );

   return new WebAsyncTask(3000, callable);

}

 

 

@RequestMapping(value="/longtimetask",method = RequestMethod.GET)

public WebAsyncTask longTimeTask(){

   System.out.println("/longtimetask被调用 thread id is : " + Thread.currentThread().getId());

   Callable<ModelAndView> callable = newCallable<ModelAndView>() {

       public ModelAndView call() throws Exception {

            Thread.sleep(3000); //假设是一些长时间任务

            ModelAndView mav = newModelAndView("longtimetask");

            mav.addObject("result","执行成功");

            System.out.println("执行成功 thread id is : " + Thread.currentThread().getId());

            return mav;

       }

   };

   

   

   WebAsyncTask asyncTask = new WebAsyncTask(2000, callable);

   asyncTask.onTimeout(

           new Callable<ModelAndView>() {

                public ModelAndView call()throws Exception {

                    ModelAndView mav = new ModelAndView("longtimetask");

                   mav.addObject("result", "执行超时");

                    System.out.println("执行超时 thread id is " +Thread.currentThread().getId());

                    return mav;

                }

           }

   );

   return new WebAsyncTask(3000, callable);

}

 

异常处理

貌似没什么差别,在Controller中的处理和之前同步模式的处理是一样一样的:

 

@ExceptionHandler(Exception.class)
    public ModelAndView handleAllException(Exception ex) {
        ModelAndView model = new ModelAndView("error");
        model.addObject("result", ex.getMessage());
        return model;
    }



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值