Detailed explanation of 5 ways of asynchronous processing in SpringMVC

This article mainly introduces 5 ways of SpringMVC asynchronous processing. This article introduces you in detail through the example code, which has a certain reference value for everyone's study or work. Friends who need it can refer to

Some time ago, I studied the principle of diamond. One of the important knowledge points is the realization of long connection, which uses the asynchronous processing of servlet. The biggest advantage of asynchronous processing is that it can increase the amount of concurrency without blocking the current thread. In fact, Spring MVC also supports asynchronous processing. This article records the relevant technical points.

Asynchronous processing demo

If you want to enable asynchronous return, you need to turn on @EnableAsync. In the following code, DeferredResult is used for asynchronous processing.

After the request comes in, first create the DeferredResult object and set the timeout period to 60 seconds. Then specify the callback of DeferredResult when asynchronous completion and waiting timeout. Synchronous processing only needs to create an asynchronous one, and then return DeferredResult. In this way, after Spring MVC has processed the request, it will not immediately return the response to the client, and will wait for the completion of the DeferredResult. If the DeferredResult is not processed within 60 seconds, a timeout will be triggered, and then a response will be returned to the client.

@RequestMapping(value = "/async/demo")
public DeferredResult<String> async(){
 // 创建 DeferredResult,设置超时时间 60s
 DeferredResult<String> deferredResult = new DeferredResult<>((long)60 * 1000);

 String uuid = UUID.randomUUID().toString();
 Runnable callback = () -> manager.remove(deferredResult, uuid);
 // 设置完成和超时的回调
 deferredResult.onCompletion(callback);
 deferredResult.onTimeout(callback);

 // 创建异步任务
 manager.addAsyncTask(deferredResult, uuid);

 // 同步返回 DeferredResult
 return deferredResult;
}

For asynchronous tasks, the DeferredResult object needs to be held. At the end of the asynchronous processing, you need to manually call DeferredResult.setResult to complete the output. When calling setResult, the data output is written to the client, and then the asynchronous completion event is triggered to execute the callback.

task.getDeferredResult().setResult(ConfigJsonUtils.toJsonString(map));

Use DeferredResult for asynchronous processing

DeferredResult This class represents a delayed result. DeferredResult can be used in asynchronous tasks, and other threads can obtain DeferredResult and set the return data of DeferredResult. Usually you can use thread pools, queues, etc. to cooperate with DeferredResult to achieve asynchronous processing.

According to the official description, the Spring MVC processing flow is as follows:

1. Save the DeferredResult returned by the controller in a memory queue or collection;
2. Spring MVC calls request.startAsync() to enable asynchronous;
3. DispatcherServlet and all Filters exit the current request thread;
4. Business applications are set in the asynchronous thread For the return value of DeferredResult, Spring MVC will send the request
again ; 5. DispatcherServlet is called again, and the return value of DeferredResult is used;

Use Callable for asynchronous processing

Using Callable for asynchronous processing is similar to DeferredResult. The difference is that Callable will be handed over to the TaskExecutor specified by the system for execution.

According to the official description, the Spring MVC processing flow is as follows:

1. The controller returns the Callable;
2. Spring MVC calls request.startAsync() to turn on asynchronous and submits the Callable to a task thread pool;
3. DispatcherServlet and all Filters exit the current request thread;
4. The business application returns the value in the asynchronous thread , Spring MVC will send the request again;
5. DispatcherServlet is called again, and the return value of Callable is used;

@RequestMapping(value = "/async/demo")
public Callable<String> async(){
 Callable<String> callable = () -> String.valueOf(System.currentTimeMillis());
 // 同步返回
 return callable;
}

Use ListenableFuture for asynchronous processing

ListenableFuture as the return value, similar to DeferredResult. Users also need to handle asynchronous threads by themselves, but timeouts and completion callbacks are not supported, and they need to be handled by themselves.

@RequestMapping(value = "/async/demo")
public ListenableFuture<String> async(){
 ListenableFutureTask<String> ListenableFuture= new ListenableFutureTask<>(() -> {
  return String.valueOf(System.currentTimeMillis());
 });
 Executors.newSingleThreadExecutor().submit(ListenableFuture);
 return ListenableFuture;
}

Use ResponseBodyEmitter for asynchronous processing

Both DeferredResult and Callable can only return an asynchronous value. If you need to return multiple objects, use ResponseBodyEmitter. Each object returned will be processed by HttpMessageConverter and written back to the output stream. If you want to set more return data, such as header, status, etc., you can return ResponseBodyEmitter as the entity data of ResponseEntity.

@RequestMapping("/async/responseBodyEmitter")
public ResponseBodyEmitter responseBodyEmitter(){
 ResponseBodyEmitter responseBodyEmitter=new ResponseBodyEmitter();

 Executors.newSingleThreadExecutor().submit(() -> {
  try {
   responseBodyEmitter.send("demo");
   responseBodyEmitter.send("test");
   responseBodyEmitter.complete();
  } catch (Exception ignore) {}
 });

 return responseBodyEmitter;
}

Use StreamingResponseBody for asynchronous processing

If you want to skip the automatic conversion of the return value and write the output stream directly to the OutputStream, you can use StreamingResponseBody. It can also be returned as the entity data of ResponseEntity.

@RequestMapping("/async/streamingResponseBody")
public StreamingResponseBody streamingResponseBody(){
 StreamingResponseBody streamingResponseBody = outputStream -> {
  Executors.newSingleThreadExecutor().submit(() -> {
   try {
    outputStream.write("<html>streamingResponseBody</html>".getBytes());
   } catch (IOException ignore) {}
  });
 };
 return streamingResponseBody;
}

Comparison of various processing methods

image.png

The latest high-frequency interview questions collected in 2021 (all organized into documents), there are a lot of dry goods, including mysql, netty, spring, thread, spring cloud, jvm, source code, algorithm and other detailed explanations. There are also detailed learning plans and interviews. Questions, etc., friends who need to obtain these content, please add Q Junyang: 547998459

Guess you like

Origin blog.csdn.net/p1830095583/article/details/114880822