Directorio de artículos
La diferencia entre solicitud asincrónica y llamada asincrónica
- Los escenarios de uso de los dos son diferentes. Solicitudes asíncronas se utilizan para resolverlos
并发请求对服务器造成的压力
,提高对请求的吞吐量
y llamadas asíncronas se utilizan做一些非主线流程且不需要实时计算和响应的任务
, por ejemplo, para sincronizar los registros a Kafka para el análisis de registro. - Las solicitudes asincrónicas son posibles
一直等待response响应的
y los resultados deben devolverse al cliente; mientras que las llamadas asincrónicas, a menudo会马上返回给客户端响应
completamos la solicitud completa. En cuanto a la llamada asincrónica, el fondo de la tarea se ejecuta lentamente por sí mismo y al cliente no le importa.
Prefacio
Solicitud síncrona Solicitud
asíncrona
Características:
- Sí
先释放容器分配给请求的线程与相关资源
, reduce la carga en el sistema y libera la solicitud del hilo asignado por el contenedor, la respuesta se retrasará.后台耗时处理完成(例如长时间的运算)时再对客户端进行响应。
- En una palabra: aumente el rendimiento del servidor de las solicitudes de los clientes
- (
实际生产上我们用的比较少
, Si la cantidad de solicitudes simultáneas es grande通过nginx把请求负载到集群服务的各个节点上来分摊请求压力
, por supuesto, estaremos bien通过消息队列来做请求的缓冲
).
Implementación de solicitud asincrónica
1. Forma de servlet para lograr una solicitud asincrónica
@RequestMapping(value = "/email/servletReq", method = RequestMethod.GET)
public void servletReq(HttpServletRequest request, HttpServletResponse response) {
AsyncContext asyncContext = request.startAsync();
//设置监听器:可设置其开始、完成、异常、超时等事件的回调处理
asyncContext.addListener(new AsyncListener() {
@Override
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("超时了...");
//做一些超时后的相关操作...
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("线程开始");
}
@Override
public void onError(AsyncEvent event) throws IOException {
System.out.println("发生错误:" + event.getThrowable());
}
@Override
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("执行完成");
//这里可以做一些清理资源的操作...
}
});
//设置超时时间
asyncContext.setTimeout(20000);
asyncContext.start(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
System.out.println("内部线程:" + Thread.currentThread().getName());
asyncContext.getResponse().setCharacterEncoding("utf-8");
asyncContext.getResponse().setContentType("text/html;charset=UTF-8");
asyncContext.getResponse().getWriter().println("这是异步的请求返回");
} catch (Exception e) {
e.printStackTrace();
System.out.println("异常:" + e);
}
//异步请求完成通知
//此时整个请求才完成
asyncContext.complete();
}
});
//此时之类 request的线程连接已经释放了
System.out.println("主线程:" + Thread.currentThread().getName());
}
2.Callable
Los parámetros devueltos por el controlador用Callable包裹即可
Puede heredar la clase WebMvcConfigurerAdapter / implementar la interfaz WebMvcConfigurer (se recomienda SpringBoot2.0) para establecer el grupo de subprocesos predeterminado y el procesamiento del tiempo de espera
La interfaz utiliza Callable para decorar los parámetros de retorno.
@RequestMapping(value = "/email/callableReq", method = RequestMethod.GET)
@ResponseBody
public Callable<String> callableReq() {
System.out.println("外部线程:" + Thread.currentThread().getName());
return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(10000);
System.out.println("内部线程:" + Thread.currentThread().getName());
return "callable!";
}
};
}
La clase de configuración establece el grupo de subprocesos predeterminado y el manejo del tiempo de espera
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private ThreadPoolTaskExecutor myThreadPoolTaskExecutor;
@Override
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
//处理 callable超时
configurer.setDefaultTimeout(60 * 1000);
configurer.setTaskExecutor(myThreadPoolTaskExecutor);
configurer.registerCallableInterceptors(timeoutCallableProcessingInterceptor());
}
@Bean
public TimeoutCallableProcessingInterceptor timeoutCallableProcessingInterceptor() {
return new TimeoutCallableProcessingInterceptor();
}
}
3.WebAsyncTask
将Controller返回的参数用WebAsyncTask包裹
De manera similar al uso invocable, puede, también puede configurar uno para WebAsyncTask 超时回调
, puede lograr el procesamiento del tiempo de espera
Puede heredar la clase WebMvcConfigurerAdapter / implementar la interfaz WebMvcConfigurer (se recomienda SpringBoot2.0) para establecer el grupo de subprocesos predeterminado y el procesamiento del tiempo de espera
@RequestMapping(value = "/email/webAsyncReq", method = RequestMethod.GET)
@ResponseBody
public WebAsyncTask<String> webAsyncReq() {
System.out.println("外部线程:" + Thread.currentThread().getName());
Callable<String> result = () -> {
System.out.println("内部线程开始:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(4);
} catch (Exception e) {
e.printStackTrace();
}
logger.info("副线程返回");
System.out.println("内部线程返回:" + Thread.currentThread().getName());
return "success";
};
WebAsyncTask<String> wat = new WebAsyncTask<String>(3000L, result);
wat.onTimeout(new Callable<String>() {
@Override
public String call() throws Exception {
return "超时";
}
});
return wat;
}
4.Resultado diferido
DeferredResult puede hacer frente a algunos de 相对复杂一些的业务逻辑
los la mayoría de los que es importante 可以在另一个线程里面进行业务处理及返回
, nos podemos comunicar entre dos hilos sin ninguna relación .
Puede heredar la clase WebMvcConfigurerAdapter / implementar la interfaz WebMvcConfigurer (se recomienda SpringBoot2.0) para establecer el grupo de subprocesos predeterminado y el procesamiento del tiempo de espera
@RequestMapping(value = "/email/deferredResultReq", method = RequestMethod.GET)
@ResponseBody
public DeferredResult<String> deferredResultReq() {
System.out.println("外部线程:" + Thread.currentThread().getName());
//设置超时时间
DeferredResult<String> result = new DeferredResult<String>(60 * 1000L);
//处理超时事件 采用委托机制
result.onTimeout(new Runnable() {
@Override
public void run() {
System.out.println("DeferredResult超时");
result.setResult("超时了!");
}
});
result.onCompletion(new Runnable() {
@Override
public void run() {
//完成后
System.out.println("调用完成");
}
});
myThreadPoolTaskExecutor.execute(new Runnable() {
@Override
public void run() {
//处理业务逻辑
System.out.println("内部线程:" + Thread.currentThread().getName());
//返回结果
result.setResult("DeferredResult!!");
}
});
return result;
}