The key to high performance: the asynchronous Pattern of Spring MVC

Source: Internet
Author: User

I admit that there are some headline parties, but in fact it's true that there are many articles about "async" processing, but I'm still going to publish this article that I've written for a long time, but I've never published it, with a much simpler view of the async pattern.

What is asynchronous mode

To know what an asynchronous pattern is, you first need to know what the synchronization mode is, and first look at the most typical synchronization mode:

(Fig. 1)

Browser initiates the request, the Web server opens a thread processing, finishes processing to return the processing result to the browser. There seems to be nothing to say, most Web servers are handled like this. Now think about what happens if you need to call a business logical server on the back end of the process?

(Fig. 2)

Tune it, as shown, the request processing thread will wait for return after call, itself in a blocking state. This is also the practice of most Web servers, generally this is enough, why? A "long-time processing service" Call is usually not much, and the number of requests is actually not many. If not, what will happen to this model? -The problem is the shortage of request processing threads! Because the total number of request processing threads is limited, if a similar request is made, all the processing threads are in a blocked state, the new request cannot be processed, and the server's throughput capacity is affected. To get the most out of the server's performance, use Async, which is the "key to high performance" as the title says. Now let's look at how async is:

(Fig. 3)

The biggest difference is that the request processing thread uses the "invoke" approach to the background processing call, which means that the request processing thread is "free" after it has been called, so that it can proceed to process other requests, and when the backend processing is complete, it hooks up a callback processing thread to process the result of the call. This callback processing thread and the request processing thread may be a thread in the thread pool that is completely free from each other and is returned to the browser by this callback processing thread. This is the asynchronous process.

The improvements are obvious, the request processing thread does not need to be blocked, its ability is more fully used, resulting in increased server throughput capacity.

The use of Spring MVC--defferedresult

To use spring MVC's async features, you first need to make sure that you are using a servlet version of 3.0 or later, as configured in Maven:

    <Dependency>      <groupId>Javax.servlet</groupId>      <Artifactid>Javax.servlet-api</Artifactid>      <version>3.1.0</version>      <Scope>Provided</Scope>    </Dependency>    <Dependency>      <groupId>Org.springframework</groupId>      <Artifactid>Spring-webmvc</Artifactid>      <version>4.2.3.RELEASE</version>    </Dependency>

The servlet version I am using here is the 3.1.0,spring MVC version is 4.2.3, which is recommended to use the latest version.

Because of the good encapsulation of spring MVC, asynchronous functionality is surprisingly simple to use. The traditional controller for synchronous mode is to return Modelandview, while the asynchronous pattern is to return deferredresult<modelandview>.

See this example:

@RequestMapping (value= "/asynctask", method =requestmethod.get) Public deferredresult<modelandview>Asynctask () {Deferredresult<ModelAndView>Deferredresult =NewDeferredresult<modelandview>(); System.out.println ("/asynctask Call! Thread ID is: "+Thread.CurrentThread (). GetId ()); Longtimeasynccallservice.makeremotecallandunknownwhenfinish (NewLongtermtaskcallback () {@Override Public voidcallback (Object result) {System.out.println ("Asynchronous call execution complete, thread ID is:" +Thread.CurrentThread (). GetId ()); Modelandview Mav=NewModelandview ("Remotecalltask"); Mav.addobject ("Result", result);        Deferredresult.setresult (MAV); }    });}

Longtimeasynccallservice is a service class that I write that simulates a long asynchronous invocation, calls it back immediately, and when it's done, hooks up a thread to invoke the callback function we provided, as described in Figure 3, with the following code:

 Public InterfaceLongtermtaskcallback {voidcallback (Object result);} Public classLongtimeasynccallservice {Private Final intCorepoolsize = 4; Private Final intNeedseconds = 3; PrivateRandom random =NewRandom (); PrivateScheduledexecutorservice Scheduler =Executors.newscheduledthreadpool (corepoolsize);  Public voidMakeremotecallandunknownwhenfinish (Longtermtaskcallback callback) {System.out.println ("Complete this task requires:" + needseconds + "seconds"); Scheduler.schedule (NewRunnable () {@Override Public voidrun () {Callback.callback ("Long-time asynchronous call complete.");    }}, "This is the result of processing:)", timeunit.seconds); }}

The result of the output is:

/asynctask Call! Thread ID is:46
Required to complete this task: 3 seconds
Asynchronous call execution complete, thread ID is:47

This shows that the thread that returned the result and the request processing thread are not the same thread.

There's another one called Webasynctask.

Returning defferedresult<modelandview> is not the only way to do this, and you can return Webasynctask to implement "async", but slightly differently, The difference is that it is not necessary for us to take the initiative to call callback if we return to Webasynctask, see example:

@RequestMapping (value= "/longtimetask", method =requestmethod.get) Public webasynctask longtimetask () {System.out.println ("/longtimetask is called thread ID is:" +Thread.CurrentThread (). GetId ()); callable <ModelAndView>callable =NewCallable<modelandview>() {         PublicModelandview Call ()throwsException {thread.sleep (3000);//Suppose it was some long time taskModelandview Mav =NewModelandview ("Longtimetask"); Mav.addobject ("Result", "execution succeeded"); System.out.println ("Execution succeeded thread ID is:" +Thread.CurrentThread (). GetId ()); returnMav;    }    }; return NewWebasynctask (callable);}

Its core is a callable<modelandview> in fact, it is possible to return directly to callable<modelandview>, but we have packed a layer here to do the "timeout processing" mentioned later. The difference between this and the previous scenario is that the callable call method is not directly called, but is called, executed, and printed by spring MVC with a working thread after Longtimetask returns:

/longtimetask is called the thread ID is:56
Execute success Thread ID is:57

Visible is actually performed by different threads, but this webasynctask does not conform to the technical specifications described in Figure 3, it simply transfers the task of the request processing thread to another worker thread.

Processing timeout

If the "long-time Processing task" has not returned, then we should not allow the client to wait indefinitely, we have to get a "timeout" out.

(Fig. 4)

In fact, the "Timeout processing thread" and "Callback processing thread" may be a thread in the thread pool, and I'll draw them apart for clarity. Adding this timeout is very simple in spring MVC, take the Webasynctask code first to change it:

@RequestMapping (value= "/longtimetask", method =requestmethod.get) PublicWebasynctask Longtimetask () {System.out.println ("/longtimetask is called thread ID is:" +Thread.CurrentThread (). GetId ()); Callable<ModelAndView> callable =NewCallable<modelandview>() {         PublicModelandview Call ()throwsException {thread.sleep (3000);//Suppose it was some long time taskModelandview Mav =NewModelandview ("Longtimetask"); Mav.addobject ("Result", "execution succeeded"); System.out.println ("Execution succeeded thread ID is:" +Thread.CurrentThread (). GetId ()); returnMav;            }    }; Webasynctask Asynctask=NewWebasynctask (2000, callable); Asynctask.ontimeout ( New Callable<modelandview> () {public Modelandview call () throws Exception {M                    Odelandview Mav = new Modelandview ("Longtimetask");                    Mav.addobject ("Result", "Execution timeout");                    SYSTEM.OUT.PRINTLN ("Execute timeout thread ID is:" + thread.currentthread (). GetId ());                return MAV;    }            }    ); return NewWebasynctask (3000, callable);}

Pay attention to the red font part of the code, which is mentioned earlier why callable also outsource a layer of reason, to Webasynctask set a timeout callback, can implement timeout processing, in this example, the normal processing takes 3 seconds, and the timeout is set to 2 seconds, so there will definitely be a timeout, Execute print log as follows:

/longtimetask is called the thread ID is:59
Execution Timeout thread ID is:61
Execute success Thread ID is:80

Well? Clearly timed out, how can "execute success"? Timeout time-out, timeout does not interrupt the normal execution process, but note that after the time-out we gave the client a "timeout" result, then even if the normal processing process succeeds, the client will not receive the normal processing success results, the problem is: The client saw "timeout", In fact, the operation is not successful, the client does not know, but usually this is not a big problem, because users in the browser to refresh a bit better. :D

OK, let's look at the Defferedresult method's timeout:

@RequestMapping (value = "/asynctask", method =requestmethod.get) PublicDeferredresult<modelandview>Asynctask () {Deferredresult<ModelAndView> Deferredresult =NewDeferredresult<modelandview> (2000L); System.out.println ("/asynctask Call! Thread ID is: "+Thread.CurrentThread (). GetId ()); Longtimeasynccallservice.makeremotecallandunknownwhenfinish (NewLongtermtaskcallback () {@Override Public voidcallback (Object result) {System.out.println ("Asynchronous call execution complete, thread ID is:" +Thread.CurrentThread (). GetId ()); Modelandview Mav=NewModelandview ("Remotecalltask"); Mav.addobject ("Result", result);            Deferredresult.setresult (MAV); }        }); Deferredresult.ontimeout ( New Runnable () {@Override public void run () {SYSTEM.OUT.PRINTLN ("Asynchronous call execution timed out!") Thread ID is: "+ thread.currentthread (). GetId ()); Modelandview Mav = new Modelandview ("Remotecalltask"); Mav.addobject ("Result", "Asynchronous Call Execution timeout"); Deferredresult.setresult (MAV); } }); returnDeferredresult; }

Very similar, right, I set the timeout to 2 seconds, and the normal processing takes 3 seconds, must be timed out, the execution result is as follows:

/asynctask Call! Thread ID is:48
Required to complete this task: 3 seconds
Asynchronous call execution timed out! Thread ID is:51
Asynchronous call execution complete, thread ID is:49

Exactly as we had expected.

Exception handling

There seems to be no difference, the processing in the controller is the same as the previous synchronization mode:

    @ExceptionHandler (Exception.  Class)    public  modelandview handleallexception (Exception ex) {        new Modelandview ("error");        Model.addobject ("Result", Ex.getmessage ());         return model;    }

and another global exception to deal with what, and the past practices are the same, this is not the table.

The key to high performance: the asynchronous Pattern of Spring MVC

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.