您的位置:首页 > 编程语言 > Java开发

Spring MVC的异步模式

2016-09-09 14:02 246 查看
典型的同步模式:



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



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








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

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



Spring MVC的使用——DefferedResult







使用的Servlet版本是3.1.0,Spring
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;

    }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: